reddit / emacs

re-search-backward and looking-at where a leading space is significant

tinkerorb · 2022-11-16 13:19
I've got a case where I use `re-search-backward` looking for something akin to `"[[:blank:]][[:alpha:]]".` While the leading whitespace is syntactically significant, it's actually the location of `[[:alpha:]]` that I am interested in. So given a few examples that for the sake of the example all start at buffer pos 1000: **A**) `" blabla"` **B**) `" blabla"` **C**) `"blabla"` `re-search-backward` would correctly return 1000 for both **A** and **B**, but it's actually the return values of 1 and 3 that I really want here. I can't just remove the `[[:blank:]]` because I don't want to match **C** where there is no leading whitespace. So I'm wondering if there is any alternative function or grouping trick where I can search backwards for a regex but get the position of a specific group in the regex back, or similar to font-lock-keywords be able to specify a regex for leading/surrounding text. Similarly, given the same example A I would like to use looking-at if the point is at position 1. For now I use `(and (looking-at "[[:alpha:]]") (looking-back "[[:blank:]]))`
7890yuiop · 2022-11-16 13:56
`match-beginning` takes an argument.
akirakom · 2022-11-16 14:01
`(rx (* blank) symbol-start)` or `(rx (* blank) word-start)`?
tinkerorb · 2022-11-16 14:41
That would work, but I shot myself in the foot here by simplifying my example. The actual word that I just used `[[:alpha:]]+` for in the example is actually a set of specific keywords. So `symbol-start` and `word-start` are too generic to work for me. I've tried figuring out if the regex syntax that those translate into can somehow be used for my case, but so far I haven't come up with anything.
tinkerorb · 2022-11-16 14:42
That works! But it is kind of awkward how that function depends on the last regex search, I would have to say.
arthurno1 · 2022-11-16 20:31
> it is kind of awkward how that function depends on the last regex search Sure, unfortunately, reg searches use global state in Emacs. You will see lots of docs saying function this or that does not modify match state.
arthurno1 · 2022-11-16 20:48
Is it a hard requirement to do it only by a regex? Sometimes, in Elisp, it is easier to combine a regex or two with some Elisp to achieve what you are looking for. Thought of something like this: (defun my/match () (save-excursion (when (re-search-backward "[ \t]+[a-z]+" nil t) (skip-chars-forward " \t") (point)))) Just as a rough idea. I don't know how do you use that position, but if you are using the match to move the cursor to that point anyway, then you can skip save-recursion and to return the point.
7890yuiop · 2022-11-16 21:15
What else should it depend upon? :)
tinkerorb · 2022-11-16 21:24
What I mean is that I would like to see something a bit more functional. Now, Emacs Lisp doesn't claim to be a purely functional language in any way, and I know side effects are very common. It's just my preferences speaking. After trying it out I got the impression that this only works if you make the call to `match-beginning` immediately following the regex evaluation. No nesting it in an if-form, etc, or I got flaky results. Also something that makes my functional mindset go "brrrr...." :) But at the end of the day, using `match-beginning` works and has shown to be the most concise way of achieving what I wanted, so...
tinkerorb · 2022-11-16 21:29
Not a hard requirement, no. I considered a solution similar to this first, but got to thinking that there might be a less wordy way of achieving it. :)
7890yuiop · 2022-11-16 22:09
> No nesting it in an if-form, etc, or I got flaky results. Yep, you need to grab what you need from the match data while you can still guarantee that it's in the state you require, as any arbitrary intervening code might involve a search behind the scenes. Also see the `save-match-data` macro. I suggest reading `C-h i g (elisp)Match Data`
arthurno1 · 2022-11-17 05:23
I understand; I am not sure what you are doing, but even if you use capture groups you will have to call match-beginning as you got answered in another comment previously. It really is up to you how you wish to write your code, depending on what you are doing. If you are just moving the cursor, you can omit save-excursion and (point) and you really just have three lines of code, which you can't skip anyway, even with capturing groups. Capturing groups are maybe more efficient, but in such a simple case, you would probably need to parse gigabytes of text to notice it?