Search code examples
emacselispfind-grep

The lisp that convert string and grep in emacs?


I have a file formatted as

abc|<hoge>
a|<foo> b|<foo> c|<foo>
family|<bar> guy|<bar>
a|<foo> comedy|<bar> show|<foo>
action|<hoge>

and want to search search strings by raw (Like "a comedy show" instead of a|<foo> comedy|<bar> show|<foo>) on emacs.

I believe using grep on lisp would be the easiest answer but I have not yet figured out how. Would someone enlighten me?


Solution

  • Well, grep is a separate program (which you could also use). In Emacs, you'd use the function search-forward-regexp, which you can run using either M-x (hold Meta, usually Alt key, and press x) and then type search-forward-regexp and press Return.

    You'll then need to key in the regexp to search. Put simply, it seems like you want to ignore |< something >, which in Emacs's variety of regexes is:

     |<[a-z]+> 
    

    so you might search for e.g.

     a|<[a-z]+> comedy|<[a-z]+> show|<[a-z]+>
    

    You can create a Lisp function to convert a string this way, by splitting it on spaces and adding the regex sequences:

    (defun find-string-in-funny-file (s)                        ; Define a function
      "Find a string in the file with the |<foo> things in it." ; Document its purpose
      (interactive "sString to find: ")                         ; Accept input if invoked interactively with M-x
      (push-mark)                                               ; Save the current location, so `pop-global-mark' can return here
                                                                ; (usually C-u C-SPC)
      (goto-char 0)                                             ; Start at the top of the file
      (let ((re (apply #'concat                                 ; join into one string…
                       (cl-loop 
                        for word in (split-string s " ")        ; for each word in `s'
                        collect (regexp-quote word)             ; collect that word, plus
                        collect "|<[a-z]+> "))))                ; also the regex bits to skip
        (search-forward-regexp                                  ; search for the next occurrence
         (substring re 0 (- (length re) 2)))))                  ; after removing the final space from `re'
    

    You can explore what those functions each do in the (online) Emacs Lisp manual; for example, pick from the menu "Help→Describe→Function" or press C-h f (Control+h, then f) and type interactive (RET) for the manual's documentation of that special form.

    If you paste the above (defun) into the *scratch* buffer, and position the cursor after the final ) at the end, you can press C-j to evaluate it, and the function will remain with you until you close Emacs.

    If you save it in a file named something .el, you can use M-x load-file to load it again in future.

    If you then load your "funny" file, and type M-x find-string-in-funny-file, it'll search your file for your string, and leave the cursor on the string. If it's not found, you'll see a message to that effect.

    BUGS: The function is less than spectacular style