Is it possible to add own character classes to emacs in order to use them in regular expressions?
Let's say, i want to add a class [[:consonant:]] which matches all letters that are not vowels in order to avoid writing [b-df-hj-np-tv-z] all the time (and yes, i am aware that my shortcut is almost as long as the term i want to avoid, take it as a simplification of my problem).
Is this possible at all or do i have to use format or concat, respectively? If it is possible, how do i do that?
An MWE could be like this:
(defun myfun ()
"Finds clusters of three or more consonants"
(interactive)
(if (search-forward-regexp "[b-df-hj-np-tv-z]\\{3,\\}")
(message "Yepp, here is a consonant cluster.")
))
(defun myfun-1 ()
"Should also find clusters of three or more consonants."
(interactive)
(if (search-forward-regexp "[[:consonant:]]\\{3,\\}")
(message "Yepp, here is a consonant cluster.")
))
Both functions myfun and myfun-1 should do the very same thing.
One step further i'd like to know if it is possible to put whole expressions in such "shortcuts", like
[[:ending:]] ==> "\\(?:en\\|st\\|t\\|e\\)"
Jordon-Biondo is correct, you cannot extend Emacs' character classes for regexp search. If you peek into Emacs' source code, you can see these defined in the routine re_wctype_parse on line 1510(ish) of regex-emacs.c. So adding to these natively would require modifying the .c file and rebuilding.
I do not believe you can do this. But there is something similar that was recently released in the ample-regexp package found HERE. This was taken from the readme as an example:
(define-arx h-w-rx
'((h "Hello, ")
(w "world"))) ;; -> hello-world-rx
(h-w-rx h w) ;; -> "Hello, world"
(h-w-rx (* h w)) ;; -> "\\(?:Hello, world\\)*"
You could use this to define a wide range of aliases in one big define-arx.
Related
Since version 22 of Emacs, we can use \,(function) for manipualting (parts of) the regex-search result before replacing it. But – this is mentioned often, but nonetheless still the truth – we can use this construct only in the standard interactive way. (Interactive like: By pressing C-M-% or calling query-replace-regexp with M-x.)
As an example:
If we have
[Foo Bar 1900]
and want to get
[Foo Bar \function{foo1900}{1900}]
we can use:
M-x query-replace-regexp <return>
\[\([A-Za-z-]+\)\([^0-9]*\) \([0-9]\{4\}\)\]
[\1\2 \\function{\,(downcase \1)\3}{\3}]
to get it done. So this can be done pretty easy.
In my own defun, I can use query only by replacing without freely modifying the match, or modify the prepared replaced string without any querying. The only way I see, is to serialize it in such a way:
(defun form-to-function ()
(interactive)
(goto-char (point-min))
(while (query-replace-regexp
"\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
"[\\1\\2 \\\\function{\\1\\3}{\\3}]" ))
(goto-char (point-min))
(while (search-forward-regexp "\\([a-z0-9]\\)" nil t)
(replace-match (downcase (match-string 1)) t nil)
)
)
For me the query is important, because I can't be sure, what the buffer offers me (= I can't be sure, the author used this kind of string always in the same manner).
I want to use an elisp function, because it is not the only recurring replacement (and also not only one buffer (I know about dired-do-query-replace-regexp but I prefer working buffer-by-buffer with replace-defuns)).
At first I thought I only miss something like a query-replace-match to use instead of replace-match. But I fear, I am also missing the easy and flexible way of rearrange the string the the query-replace-regexp.
So I think, I need a \, for use in an defun. And I really wonder, if I am the only one, who is missing this feature.
If you want your rsearch&replace to prompt the user, that means you want it to be interactive, so it's perfectly OK to call query-replace-regexp (even if the byte-compiler will tell you that this is meant for interactive use only). If the warning bothers you, you can either wrap the call in with-no-warnings or call perform-replace instead.
The docstring of perform-replace sadly doesn't (or rather "didn't" until today) say what is the format of the replacements argument, but you can see it in the function's code:
;; REPLACEMENTS is either a string, a list of strings, or a cons cell
;; containing a function and its first argument. The function is
;; called to generate each replacement like this:
;; (funcall (car replacements) (cdr replacements) replace-count)
;; It must return a string.
The query-replace-function can handle replacement not only as a string, but as a list including the manipulating elements. The use of concat archives building an string from various elements.
So one who wants to manipulate the search match by a function before inserting the replacement can use query-replace-regexp also in a defun.
(defun form-to-function ()
(interactive)
(goto-char (point-min))
(query-replace-regexp
"\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
(quote (replace-eval-replacement concat "[\\1\\2 \\\\function{"
(replace-quote (downcase (match-string 1))) "\\3}{\\3}]")) nil ))
match-string 1 returns the first expression of our regexp-search.
`replace-quote' helps us doublequoting the following expression.
concat forms a string from the following elements.
and
replace-eval-replacement is not documented.
Why it is in use here nevertheless, is because of emacs seems to use it internally, while performing the first »interactive« query-replace-regexp call. At least is it given by asking emacs with repeat-complex-command.
I came across repeat-complex-command (bound to [C-x M-:].) while searching for an answer in the source code of query-replace-regexp.
So an easy to create defun could be archieved by performing the standard search and replace way as told in the question and after first sucess pressing [C-x M-:] results in an already Lisp formed command, which can be copied and pasted in a defun.
Edit (perform-replace)
As Stefan mentioned, one can use perform-replace to avoid using query-replace-regexp.
Such a function could be:
(defun form-to-function ()
(interactive)
(goto-char (point-min))
(while (perform-replace
"\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
(quote (replace-eval-replacement concat "[\\1\\2 \\\\function{"
(replace-quote (downcase (match-string 1))) "\\3}{\\3}]"))
t t nil)))
The first boolean (t) is a query flag, the second is the regexp switch. So it works also perfectly, but it didn't help finding the replacement expression as easy as in using \,.
in my file, I have many instances of ID="XXX", and I want to replace the first one with ID="0", the second one with ID="1", and so on.
When I use regexp-replace interactively, I use ID="[^"]*" as the search string, and ID="\#" as the replacement string, and all is well.
now I want to bind this to a key, so I tried to do it in lisp, like so:
(replace-regexp "ID=\"[^\"]*\"" "ID=\"\\#\"")
but when I try to evaluate it, I get a 'selecting deleted buffer' error. It's probably something to do with escape characters, but I can't figure it out.
Unfortunately, the \# construct is only available in the interactive call to replace-regexp. From the documentation:
In interactive calls, the replacement text may contain `\,'
followed by a Lisp expression used as part of the replacement
text. Inside of that expression, `\&' is a string denoting the
whole match, `\N' a partial match, `\#&' and `\#N' the respective
numeric values from `string-to-number', and `\#' itself for
`replace-count', the number of replacements occurred so far.
And at the end of the documentation you'll see this hint:
This function is usually the wrong thing to use in a Lisp program.
What you probably want is a loop like this:
(while (re-search-forward REGEXP nil t)
(replace-match TO-STRING nil nil))
which will run faster and will not set the mark or print anything.
Which then leads us to this bit of elisp:
(save-excursion
(goto-char (point-min))
(let ((count 0))
(while (re-search-forward "ID=\"[^\"]*\"" nil t)
(replace-match (format "ID=\"%s\"" (setq count (1+ count)))))))
You could also use a keyboard macro, but I prefer the lisp solution.
Given a string, I want to replace all links within it with the link's description. For example, given
this is a [[http://link][description]]
I would like to return
this is a description
I used re-builder to construct this regexp for a link:
\\[\\[[^\\[]+\\]\\[[^\\[]+\\]\\]
This is my function:
(defun flatten-string-with-links (string)
(replace-regexp-in-string "\\[\\[[^\\[]+\\]\\[[^\\[]+\\]\\]"
(lambda(s) (nth 2 (split-string s "[\]\[]+"))) string))
Instead of replacing the entire regexp sequence, it only replaces the trailing "]]". This is what it produces:
this is a [[http://link][descriptiondescription
I don't understand what's going wrong. Any help would be much appreciated.
UPDATE: I've improved the regex for the link. It's irrelevant to the question but if someone's gonna copy it they may as well get the better version.
Your problem is that split-string is clobbering the match data, which
replace-regexp-in-string is relying on being unchanged, since it is going to
go use that match data to decide which sections of the string to cut out. This
is arguably a doc bug in that replace-regexp-in-string does not mention that
your replacement function must preserve the match data.
You can work around by using save-match-data, which is a macro provided for
exactly this purpose:
(defun flatten-string-with-links (string)
(replace-regexp-in-string "\\[\\[[a-zA-Z:%#/\.]+\\]\\[[a-zA-Z:%#/\.]+\\]\\]"
(lambda (s) (save-match-data
(nth 2 (split-string s "[\]\[]+")))) string))
My company has recently added some new code styling rules, and I would was wondering if there is an easy way via emacs to change a couple things w/ a regex replace.
if statements now have to look like the following:
if (expression) {
where I have many that look like so:
if(expression){
lacking the spaces. Is there an easy way to fix this?
You might be able to regexp replace it if expression is always on one line, but I'd use a throw-away function just to be safe:
(defun my-fix-style ()
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\\_<if(" nil t)
(backward-char)
(insert " ")
(forward-sexp)
(unless (looking-at "[ \t\n]")
(insert " ")))))
Just my two cents, but if I was going to do this with emacs, I'd probably avoid regular expressions and approach it in two parts. First I'd do the search to replace if( with if ( by doing a Meta-% "if(" "if (" The quote marks are just for delineation, they don't belong in the entered text. Then either answer each individual replacement query, or give it a "!" to tell it to do all replacements. Repeat the process for the closing ){ to ) {.
Off the top of my head, I'd expect the first substituion to work without issue. The second one will also get "){" combinations in loops, but if your new standard demands a space for if statements, I'd expect it to do so for loops as well, so that seems like it should be a good thing.
For context, I am something of an emacs newbie. I haven't used it for very long, but have been using it more and more (I like it a lot). Also I'm comfortable with lisp, but not super familiar with elisp.
What I need to do is bind a regular expression to a keyboard combination because I use this particular regex so often.
What I've been doing:
M-C-s ^.*Table\(\(.*\n\)*?GO\)
Note, I used newline above, but I've found that for isearch-forward-regexp, you really need to replace the \n in the regular expression with the result of C-q Q-j. This inserts a literal newline (without ending the command) enabling me to put a newline into the expression and match across lines.
How can I bind this to a key combination?
I vaguely understand that I need to create an elisp function which executes isearch-forward-regexp with the expression, but I'm fuzzy on the details. I've searched google and found most documentation to be a tad confusing.
How can I bind a regular expression to a key combination in emacs?
Mike Stone had the best answer so far -- not exactly what I was looking for but it worked for what I needed
Edit - this sort of worked, but after storing the macro, when I went back to use it later, I couldn't use it with C-x e. (i.e., if I reboot emacs and then type M-x macro-name, and then C-x e, I get a message in the minibuffer like 'no last kbd macro' or something similar)
#Mike Stone - Thanks for the information. I tried creating a macro like so:
C-x( M-C-s ^.*Table\(\(.*C-q C-J\)*?GO\) C-x)
This created my macro, but when I executed my macro I didn't get the same highlighting that I ordinarily get when I use isearch-forward-regexp. Instead it just jumped to the end of the next match of the expression. So that doesn't really work for what I need. Any ideas?
Edit: It looks like I can use macros to do what I want, I just have to think outside the box of isearch-forward-regexp. I'll try what you suggested.
You can use macros, just do C-x ( then do everything for the macro, then C-x ) to end the macro, then C-x e will execute the last defined macro. Then, you can name it using M-x name-last-kbd-macro which lets you assign a name to it, which you can then invoke with M-x TESTIT, then store the definition using M-x insert-kbd-macro which will put the macro into your current buffer, and then you can store it in your .emacs file.
Example:
C-x( abc *return* C-x)
Will define a macro to type "abc" and press return.
C-xeee
Executes the above macro immediately, 3 times (first e executes it, then following 2 e's will execute it twice more).
M-x name-last-kbd-macro testit
Names the macro to "testit"
M-x testit
Executes the just named macro (prints "abc" then return).
M-x insert-kbd-macro
Puts the following in your current buffer:
(fset 'testit
[?a ?b ?c return])
Which can then be saved in your .emacs file to use the named macro over and over again after restarting emacs.
I've started with solving your problem literally,
(defun search-maker (s)
`(lambda ()
(interactive)
(let ((regexp-search-ring (cons ,s regexp-search-ring)) ;add regexp to history
(isearch-mode-map (copy-keymap isearch-mode-map)))
(define-key isearch-mode-map (vector last-command-event) 'isearch-repeat-forward) ;make last key repeat
(isearch-forward-regexp)))) ;`
(global-set-key (kbd "C-. t") (search-maker "^.*Table\\(\\(.*\\n\\)*?GO\\)"))
(global-set-key (kbd "<f6>") (search-maker "HELLO WORLD"))
The keyboard sequence from (kbd ...) starts a new blank search. To actually search for your string, you press last key again as many times as you need. So C-. t t t or <f6> <f6> <f6>. The solution is basically a hack, but I'll leave it here if you want to experiment with it.
The following is probably the closest to what you need,
(defmacro define-isearch-yank (key string)
`(define-key isearch-mode-map ,key
(lambda ()
(interactive)
(isearch-yank-string ,string)))) ;`
(define-isearch-yank (kbd "C-. t") "^.*Table\\(\\(.*\\n\\)*?GO\\)")
(define-isearch-yank (kbd "<f6>") "HELLO WORLD")
The key combos now only work in isearch mode. You start the search normally, and then press key combos to insert your predefined string.
#Justin:
When executing a macro, it's a little different... incremental searches will just happen once, and you will have to execute the macro again if you want to search again. You can do more powerful and complex things though, such as search for a keyword, jump to the beginning of the line, mark, go to end of the line, M-w (to copy), then jump to another buffer, then C-y (paste), then jump back to the other buffer and end your macro. Then, each time you execute the macro you will be copying a line to the next buffer.
The really cool thing about emacs macros is it will stop when it sees the bell... which happens when you fail to match an incremental search (among other things). So the above macro, you can do C-u 1000 C-x e which will execute the macro 1000 times... but since you did a search, it will only copy 1000 lines, OR UNTIL THE SEARCH FAILS! Which means if there are 100 matches, it will only execute the macro 100 times.
EDIT: Check out C-hf highlight-lines-matching-regexp which will show the help of a command that highlights everything matching a regex... I don't know how to undo the highlighting though... anyways you could use a stored macro to highlight all matching the regex, and then another macro to find the next one...?
FURTHER EDIT: M-x unhighlight-regexp will undo the highlighting, you have to enter the last regex though (but it defaults to the regex you used to highlight)
In general, to define a custom keybinding in Emacs, you'd write
(define-key global-map (kbd "C-c C-f") 'function-name)
define-key is, unsurprisingly, the function to define a new key. global-map is the global keymap, as opposed to individual maps for each mode. (kbd "C-c C-f") returns a string representing the key sequence C-c C-f. There are other ways of doing this, including inputting the string directly, but this is usually the most straightforward since it takes the normal written representation. 'function-name is a symbol that's the name of the function.
Now, unless your function is already defined, you'll want to define it before you use this. To do that, write
(defun function-name (args)
(interactive)
stuff
...)
defun defines a function - use C-h f defun for more specific information. The (interactive) there isn't really a function call; it tells the compiler that it's okay for the function to be called by the user using M-x function-name and via keybindings.
Now, for interactive searching in particular, this is tricky; the isearch module doesn't really seem to be set up for what you're trying to do. But you can use this to do something similar.