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:


But my expected output is:

  • A similar question: emacs.stackexchange.com/questions/30432/… My answer there is cexp. – Tobias Oct 15 '18 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. – Jordon Biondo Oct 15 '18 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 '18 at 21:01

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()")
  (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)
  (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
  • 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 '18 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 '18 at 9:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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