I have a regexp, org-parse-regexp
which matches org items which I define to be a heading and a source block (actually, I include more stuff but I want to keep it simple). I've tested it using re-search-forward
in the buffer config.org
.
(with-current-buffer "config.org"
(goto-char (point-min))
(re-search-forward org-parse-regexp)
(match-string-no-properties 0))
And it works! Here's a first level heading with a source block.
"* Variables
#+begin_src emacs-lisp
(message \"some code\")
#+end_src"
I thought it should also work, if I try using the regexp to match org items for the buffer contents as a string instead of traversing the buffer itself.
(let ((my-org-file-contents (with-current-buffer "config.org" (buffer-string)))
(string-match org-parse-regexp my-org-file-contents)
(match-string 0 my-org-file-contents))
Surprisingly, using the same regexp I got a different result. This is the same heading as before, but the source block wasn't captured!
"* Variables
"
Hmm... I admit I am a little stumped as to why this is the case. But I decided to try just capturing a source block and see what happens.
I use a small excerpt from my source block capturing expression.
;; language
(rx "#+begin_src" (1+ blank) (group-n 7 letter (1+ (or letter "-")))
;; switches
(opt (1+ blank) (group-n 8 (1+ ":" (1+ (or letter blank)))))
;; one or more whitespace characters
(1+ white)
;; body
(group-n 9 (regexp "\\([^\000]*?\n\\)??[ \t]*")) "#+end_src"))
And swap it in for org-parse-regexp
for both the buffer and the buffer substring example.
As I expected I get the first code block of my org file when I traverse the buffer itself with re-search-forward
.
"#+begin_src emacs-lisp
(message \"some code\")
#+end_src"
I didn't expect to get anything for the substring example, but I was amazed when it gave me a source block! Albeit, not the first one (it was in fact the 92nd code block in my org file). It's also the first one with a switch.
"#+begin_src emacs-lisp :tangle yes
(message "Hi, I'm number 92!")
#+end_src"
After deleting the :tangle yes
switch, I tried again and I got the next source block with a switch. Clearly, this has to do with the switch or the whitespace around it.
I realized that one of the problems was the (1+ white)
in my regexp which is the same as [[:space:]]+
. When I replaced this with "\n"
both methods caught the first source block in the file.
I got the source block part working but I still need to make changes like this to the rest of my regexp, but I don't understand.
Why does this change made a difference? And in general why does a regexp that matches targets using re-search-forward
in a buffer not necessary match the same things when used with string-match
?
UPDATE: The way I reproduced the problem:
Use (1+ white)
instead of "\n"
in the regular expression.
(let (my-org-string (with-current-buffer "config.org"
(buffer-substring-no-properties (point-min)
(point-max))))
(string-match org-parse-regexp my-org-string)
(match-string-no-properties 0 my-org-string))
;; ouput
"*** Variables
"
(with-currernt-buffer "config.org"
(goto-char (point-min))
(re-search-forward org-parse-regexp)
(match-string-no-properties 0))
;; output
"*** Variables
#+begin_src emacs-lisp
(message "hi")
#+end_src"
The org file looks like:
*** Variables
#+begin_src emacs-lisp
(message "hi")
#+end_src
For reference, the full regexp from my code is:
(rx (sequence
;; needs to be at beginning of line - so asteriks
;; that are in paragraphs are matched.
bol
;; heading level
(group-n 1 (1+ "*"))
;; todo name
(opt blank (group-n 2 upper upper-case (+ (or upper "-")) upper))
;; header name
blank (group-n 3 (+ (any letter punct digit)) (opt (+ blank (+ (any letter punct digit)))))
(* blank)
;; tags
(opt (group-n 4 (1+ ":" (1+ letter)) ":"))
"\n"
(opt "\n")
;; description
;; for now not "*" or "#" as it interferes with org headings and org blocks respectively
(opt (+ (group-n 5
(+ (or digit letter "[" "=" "~") (+ nonl) "\n")
(opt (+ "\n" (+ (or digit letter "[" "=" "~") (+ nonl) "\n"))))))
;; source block
(opt
(opt "\n")
(opt "#+name:" (1+ blank) (group-n 6 (1+ (or alnum "-"))))
;; language
(opt "\n")
"#+begin_src" (1+ blank) (group-n 7 letter (1+ (or letter "-")))
;; optional source arguments
(opt (1+ blank) (group-n 8 (1+ ":" (1+ letter) blank (1+ (or letter punct)))))
;; go to new line
;; was -> (1+ white)
"\n"
;; arguments
;; body
(group-n 9 (regexp "\\([^\000]*?\n\\)??[ \t]*")) "#+end_src")))
rx
form produces an invalid regexp on account of(regexp "\\[^000]*?\n\\)??[ \t]*")
introducing that closing"\\)"
without any matching opening paren (and there look to be other syntax issues with that bit). If it's awkward to pare down your original regexp, just post the full version.with-currernt-buffer
(along with the earlier "that was a typo") has me worried that you're adding code to your question by manually typing it, rather than copying and pasting from the original source in Emacs? Please ensure that you are always pasting the exact code you were using -- the potential for typos resulting in wasted time on all sides is rather high.