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.

7
  • 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
    Commented Aug 25, 2016 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
    Commented Aug 26, 2016 at 5:34
  • 1
    I think this might be another case of Bug #15107
    – npostavs
    Commented Aug 29, 2016 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" Commented Aug 30, 2016 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" Commented Aug 30, 2016 at 23:19

1 Answer 1

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 and acknowledge you have read our privacy policy.

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