6 ms·
The new-line character is an actual character "at the end" of the string though so it makes sense that $ would include the new-line character in multi-line matc
by Izmaki 3y ago
The new-line character is an actual character "at the end" of the string though so it makes sense that $ would include the new-line character in multi-line matching.
- IshKebab 3y agoYes and every implementation gets that right. The point was when multi-line matching is disabled and only Javascript, Go and Rust get that right. I'm not too surprised by PHP and Python getting it wrong. Java and C# is a slight surprise though.
- danbruc 3y agoI don't think it is correct to say some get it right and some get it wrong, it is more of an design decision.
- IshKebab 3y agoIt's possible to get design decisions wrong. Clearly people expect `$` to only match end-of-string so they did make the wrong decision. It may not have been clear it was the wrong decision at the time.
- danbruc 3y agoThings are obviously more complicated than that, lines are a complicated issue for historical reasons. There are two conventions, line termination and line separation. In case of line termination, the newline is part of the line and a string without a newline is not a [complete] line. In case of line separation, the newline is not part of the line but separates two lines. Also the way newlines are encoded is not universal.
- fauigerzigerk 3y agoWhy is this relevant when multi-line is disabled?
- danbruc 3y agoBecause even after disabling multi-line you are still dealing with line-based semantics when you use ^ or $, the newline at the end is still not part of the content. You have to use \A and \Z if you want to treat all characters as a string instead of one or multiple lines.
- burntsushi 3y ago> Because even after disabling multi-line you are still dealing with line-based semantics when you use ^ or $ No, you're not, except for this weird corner case where `$` can match before the last `\n` in a string. It's not just any `\n` that non-multiline `$` can match before. It's when it's the last `\n` in the string. See: >>> re.search('cat$', 'cat\n') <re.Match object; span=(0, 3), match='cat'> >>> re.search('cat$', 'cat\n\n') >>> This is weird behavior. I assume this is why RE2 didn't copy this. And it's certainly why I followed RE2 with Rust's regex crate. Non-multiline `$` should only match at the end of the string. It should not be line-aware. In regex engines like Python where it has the behavior above, it is only "partially" line-aware, and only in the sense that it treats the last `\n` as special.
- danbruc 3y agoBut that is exactly what it means, the end of the line is before the terminating newline or at the end of the string if there is no terminating newline. Both ^ and $ always match at start or end of lines, \A and \Z match at the start or end of the string. The difference between multi-line and not is whether or not internal newlines end and start lines, it does not change the semantics from end of line to end of string. And if you are not in multi-line mode but have internal newlines, then you might also want single-line/dot-all mode. One could certainly have a debate whether this behavior is too strongly tied to the origins of regular expressions and now does more harm than good, but I am not convinced that this would be an easy and obvious choice to have breaking change.
- dfawcus 3y agoGiven that in unix they sort started as: ed -> sed ed -> grep The line oriented mature makes sense. There is some sed multi-line capability if one uses the hold space, but it is much easier to just use awk.
- tankenmate 3y agoNot quite, there are standards for this behaviour (formal and de jure).
- danbruc 3y agoAnd the ones that do not match cat\n with cat$ arguably have it wrong. Both ^ and $ anchor to the start and end of lines, not to the start and end of strings, whether in multi-line mode or not.
- noirscape 3y agoIt's not wrong actually. It's the difference between BRE and ERE, which are the two different POSIX standards that define regex. In BRE the $ should always match the end of the string (the spec specifically says it should match the string terminator since "newlines aren't special characters"), while the ERE spec says it should match until the end of the line. The real issue is that no language nowadays "just" implements BRE or ERE since both specs are lacking in features. Most languages instead implement some variant of Perl's regex instead (often called PCRE regex because of the C library that brought Perl's regex to C), which as far as I can tell isn't standardized, so you get these subtle differences between implementations.
- deleted 3y ago[deleted]
- mnw21cam 3y agoThe article is about when multi-line is disabled.