Live data from Hacker News

Regex character "$" doesn't mean "end-of-string"

sethmlarson.dev

301–310 of 382 posts

Re: Regex character "$" doesn't mean "end-of-string"

#301
Ugh. Whenever I hear people talk about regular expressions as a singular language or standard, I die a little inside.

PSA: Regex security is particular to each implementation flavor. Please know the nuances of a particular kind and be unambiguously precise.

Re: Regex character "$" doesn't mean "end-of-string"

#302
post #201
post #98

Earlier quoted context omitted.

Exactly the same here, re: Perl. My brain thinks in Perl's regex language and then I have to translate the inconsistent bits to the language I'm using. Especially in the shell - I'm way more likely to just drop a perl into the pipeline instead of trying to remember how sed/grep/awk (GNU or BSD?) prefer their regex.

GNU grep supports Perl regexp with -P

Using PCRE2, which doesn't behave exactly the same as Perl or PCRE1.

https://pcre.org/current/doc/html/pcre2compat.html

https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expres...

https://stackoverflow.com/questions/70273084/regex-differenc...

Re: Regex character "$" doesn't mean "end-of-string"

#303

Earlier quoted context omitted.

> It is start and end of line. You seem to have redefined “line” as “not a line”. > The confusion I’m sure redefining “line” as “nothing like what anyone reasonable would interpret as a line” will help a lot and right clear up the confusion.

The POSIX definition of a line is a sequence of non-newline characters - possibly zero - followed by a newline. Everything that does not end with a newline is not a [complete] line. So strictly speaking it would even be correct that cat$ does not match cat because there is no terminating newline, it should only match cat\n. But as lines missing a terminating newline is a thing, it seems reasonable to be less strict.

Python violates that definition however, by allowing internal newlines in strings. For example /^c[^a]t$/ matches "c\nt\n", but according to POSIX that's not a line.

I suspect the real reason for Python's behavior starts with the early decision to include the terminating newline in the string returned by IOBase.readline().

Python's peculiar choice has some minor advantages: you can distinguish between files that do and don't end with a terminating newline (the latter are invalid according to POSIX, but common in practice, especially on Windows), and you can reconstruct the original file by simply concatenating the line strings, which is occasionally useful.

The downside of this choice is that as a caller you have to deal with strings that may-or-may-not contain a terminating newline character, which is annoying (I often end up calling rstrip() or strip() on every line returned by readline(), just to get rid of the newlines; read().splitlines() is an option too if you don't mind reading the entire file into memory upfront).

My guess is that Python's behavior is just a hack to make re.match() easier to use with readline(), rather than based on any principled belief about what lines are.

Re: Regex character "$" doesn't mean "end-of-string"

#304
post #63

Isn't a string with a newline character automatically multiline? The new line is just empty but not the first line anymore.

No, it is not. 3.195 Incomplete Line A sequence of one or more non- characters at the end of the file. 3.206 Line A sequence of zero or more non- characters plus a terminating character. courtesy of [0]. See also [1] for rationale on "text file": Text File [...] The definition of "text file" has caused controversy. The only difference between text and binary files is that text files have lines of less than {LINE_MAX}…

Not everything uses POSIX maybe that's a reason for the different results.

Re: Regex character "$" doesn't mean "end-of-string"

#305
post #303

Earlier quoted context omitted.

The POSIX definition of a line is a sequence of non-newline characters - possibly zero - followed by a newline. Everything that does not end with a newline is not a [complete] line. So strictly speaking it would even be correct that cat$ does not match cat because there is no terminating newline, it should only match cat\n. But as lines missing a terminating newline is a thing, it seems reasonable to be less strict.

Python violates that definition however, by allowing internal newlines in strings. For example /^c[^a]t$/ matches "c\nt\n", but according to POSIX that's not a line. I suspect the real reason for Python's behavior starts with the early decision to include the terminating newline in the string returned by IOBase.readline(). Python's peculiar choice has some minor advantages: you can distinguish between files that do a…

Python's behavior is not a hack, it is the common behavior. $ matches at the end of the string or before the last character if that is a newline, which is logically the same as the end of a single line. But as you said, you can have additional newlines inside of the string which is also the common behavior and not specific to python. Personally I think of this as you just assume that the string is a single line and match $ accordingly, either at the end of the string or before a terminating newline, if there are additional newlines, you treat them mostly as normal characters, with the exception of dot not matching newlines unless you set the single-line/dot-all flag.

Re: Regex character "$" doesn't mean "end-of-string"

#306

Earlier quoted context omitted.

It's kind of driving me nuts that the article says ^ is "start of string" when it's actually "start of line", just like $ is "end of line". \A is apparently "start of string" like \Z is "end of string".

It’s not start of line though, unless the engine is in multiline mode. Here is the documentation for Python’s re for instance: > Matches the start of the string, and in MULTILINE mode also matches immediately after each newline. Or JavaScript: > An input boundary is the start or end of the string; or, if the m flag is set, the start or end of a line. \A and \Z are start/end of input regardless of mode… when they’re a…

Matches the EMPTY STRING at the beginning of the line is the correct definition.

Re: Regex character "$" doesn't mean "end-of-string"

#308
It's easy to get the canonical answer:

$ man pcre2syntax

Where you'll find the following block under ANCHORS AND SIMPLE ASSERTIONS:

         $           end of subject
                       also before newline at end of subject
                       also before internal newline in multiline mode
So all the cases of "newline at/before end of subject" are covered here. Then, the question becomes "what is a subject?" Is it line-by-line? Are newlines included? What if we want multiline matching? That's where re.MULTILINE comes from, it's not "multiline matching" (sort of) it's "what is the subject of the regular expression that we're matching against"

Re: Regex character "$" doesn't mean "end-of-string"

#309

Earlier quoted context omitted.

Technically, that is one of two possible interpretations, and you seem to have invented a "by definition" out of thin air. Very very technically a "newline" character indicates the start of a new line, which is why it is not called the "end-of-line" character.

I mean, the person you are responding to didn't invent the definition out of thin air... the POSIX standard did: 3.206 Line A sequence of zero or more non- characters plus a terminating character. https://pubs.opengroup.org/onlinepubs/9699919799.2018edition...

I don't know why no-one here sees this as a bad design...

If a line is missing a newline then we just disregard it?!

A way better way to deal with newline is it's a separator like comma. And like in modern languages we allow a final separator, but ignore it so that is easier for tools to generate files.

Now all combinations of characters, including newline characters, has an interpretation without dropping anything.

Re: Regex character "$" doesn't mean "end-of-string"

#310

Earlier quoted context omitted.

No, it is valid for a file to have content but no lines. Semantically many libraries treat that as a line because while \n means "the end of the last line" having just adds additional complexity the user has to handle to read the remaining input. But by the book it's not "a line". If I said "ten buckets of water" does that mean ten full buckets? Or does a bucket with a drop in it count as "a bucket of water?" If I as…

Thats beyond ridiculous. Most languages when you are reading a line from a file, and it doesn't have a \n terminator, its going to give you that line, not say, oops, this isn't a line sorry.

I don't think you can meaningfully generalize to "most languages" here. To give an example, two extremely popular languages are C and Python. Both have a standard library function to read a line from a text stream - fgets() for C, readline() for Python. In both cases, the behavior is to read up to and including the newline character, but also to stop if EOF is encountered before then. Which means that the return value is different for terminated vs unterminated final lines in both languages - in particular, if there's no \n before EOF, the value returned is not a line (as it does not end with a newline), and you have to explicitly write your code to accommodate that.
Post reply on HN