4

I've encountered a wierd situation when trying to match the first character of a string using a regex with alternatives. It seems that replacement stops when matching a single character using a period at the start of the string, but not for slightly different patterns.

Desired behavior:

"foo bar" -> "Foo Bar"

(replace-regexp-in-string
   "^.\\| ."
   #'upcase
   "foo bar")
> "Foo bar"

Notice that replacement stops and doesn't capitalize the 'b' in 'bar'. However:

(replace-regexp-in-string
   "^f\\| ."
   #'upcase
   "foo bar")
> "Foo Bar"

(replace-regexp-in-string
   "^.o\\| ."
   #'upcase
   "foo bar")
> "FOo Bar"

(replace-regexp-in-string
   "^..\\| ."
   #'upcase
   "foo bar")
> "FOo Bar"

I have tried parenthesizing all combinations of the alternatives to no effect.

I'm not concerned about beginning of string vs beginning of line ('\`' vs '^'), but FWIW this odd behavior is consistent with both patterns.

I'm observing this behavior with both emacs 24.5.1 and 25.0.95.1.

  • 1
    Take a look at it's implementation, where you'll immediately see why this is happening. I think, it can be considered a bug. – politza Aug 25 '16 at 23:05
  • 3
    I did not see immediately why this is happening, so spoiler alert, here's why : in the current implementation, the regexp is matched first against the whole string (that's normal and ok), then once again, but only against the substring that matched. This is an optimisation which leads to the bug because the substring that matched is " b" which is matched by "^.", so only the space character gets upcased. Could you please M-x report-emacs-bug ? – YoungFrog Aug 26 '16 at 5:34
  • 1
    I think this might be another case of Bug #15107 – npostavs Aug 29 '16 at 16:57
  • 2
    Not addressing the bug (if that's what it is), but just noting that you could (I think should) use capitalize, not replace-regexp-in-string: (capitalize "foo bar") => "Foo Bar" – Phil Hudson Aug 30 '16 at 23:04
  • 1
    Again, not addressing the bug, I think "\\<." may be the regexp you want. (That is: beginning of word followed by character). (replace-regexp-in-string "\\<." #'upcase "foo bar") => "Foo Bar" – Phil Hudson Aug 30 '16 at 23:19
3

There's consensus that the observed behavior is buggy and not user error / an expected limitation of regexps in emacs.

I mentioned this discussion and submitted a regression test for the bug on debbugs: GNU bug #15107 "24.3; replace-regexp-in-string wrong on `

One solution for those seeking one in the interim: If the replacements do not interact with the pattern itself, the replacement may be split at the pattern alternatives. For example:

(replace-regexp-in-string "^." #'upcase
 (replace-regexp-in-string " ." #'upcase "foo bar"))

Ultimately I changed my regexp to use the word boundary character \\< to yield the pattern "\\<." In my particular case I could have replaced the whole thing with #'capitalize.

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.