1

How can emacs lisp match balanced parenthesis? for example: "foo(bar(),hee()) out()" should be match "foo(bar(),hee())".

I try below statement but it doesn't work:

#!/usr/bin/env emacs --script

(setq str "foo(bar(),hee()) out()")
(when (string-match "foo(.*?)" str)
  (print (match-string 0 str))
)

Currently, the output is:

"foo(bar()"

But my expected output is:

foo(bar(),hee())
3
  • A similar question: emacs.stackexchange.com/questions/30432/… My answer there is cexp.
    – Tobias
    Oct 15, 2018 at 20:50
  • 1
    Not a direct answer, but whatever your use case is, you're likely going to have a much better time using syntax-ppss if you want to find balanced parens. Oct 15, 2018 at 20:54
  • 2
    @beetlej Note that regular expressions cannot do what you are asking. You would instead use something like forward-sexp to move over a balanced expression.
    – phils
    Oct 15, 2018 at 21:01

1 Answer 1

2

As phils already pointed out in his comment forward-sexp is the function that parses balanced expressions.

You could modify your example as follows to match the balanced expression with vanilla emacs:

#!/usr/bin/env emacs --script
(setq str "foo(bar(),hee()) out()")
(with-temp-buffer
  (insert str)
  (goto-char (point-min))
  (let (end)
    (when (and (search-forward "foo(" nil t)
           (condition-case err
           (setq end (scan-sexps (1- (point)) 1))
         (scan-error nil)))
      (print (buffer-substring (match-beginning 0) end))
      )))

I already pointed out in my comment that I would use cexp. In that case the modified code would be:

#!/usr/bin/env emacs --script
(setq str "foo(bar(),hee()) out()")
(require 'cexp)
(with-temp-buffer
  (insert str)
  (goto-char (point-min))
  (when (cexp-search-forward "foo\\!(\\`(\\!)" nil t)
    (print (match-string 0))))

The parts of the combined expression "foo\\!(\\`(\\!)":

  • foo matches itself
  • \!(...\!) matches a balanced expression
  • \`... at the very beginning of the balanced expression...
  • ( should be a parenthesis
2
  • The cexp version works fine in emacs editor, but when run it as script, I got below error "Cannot open load file: No such file or directory, cexp". can I use require statement in script?
    – beetlej
    Oct 17, 2018 at 2:08
  • @beetlej Emacs does not load any initialization file with --script option. So no load-path modifications from your init files are executed. Either you save cexp.el into one of the directories in the compiled-in load-path, or you set the load path in your site-start.el file, or you replace the (require 'cexp) with (load-library "/absolute/path/to/cexp.el").
    – Tobias
    Oct 17, 2018 at 9:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.