Skip to content

Multiline text and logs

One line: A pattern over a text with line breaks in it has to answer three questions the pattern does not ask by itself — do ^ and $ mean lines, does . cross a newline, and what is a newline — and the eight engines here split on all three, with Ruby using the other engines' letters for different things and Java and JavaScript alone treating a \r as part of a line ending.

Level: 201 · you have a log file, a config file, or anything with more than one line

The three questions

Question The flag Default Where it differs
Do ^/$ match at line boundaries? m / (?m) / re.M / MULTILINE no — except Ruby: always yes Ruby has no flag to turn it off
Does . cross a line break? s / (?s) / re.S / DOTALL no Ruby spells it m, and refuses (?s)
What counts as a line break? — \n only Java and JavaScript: also \r, and \r\n as a unit for the anchors

Measured

Verified output of topic_multiline_text_and_logs_sh.sh — regenerated by tools/run_examples.py, never hand-typed.

construct                    python   perl     node  ruby     java     go       rust     fancy
line anchors, no flag        no       no       no    b        no       no       no       no
line anchors, (?m)           b        b        -     b        b        b        b        b
line anchors, node m flag    no       no       b     b        no       no       no       no
CRLF line, (?m)^b$           no       no       -     no       b        no       no       no
CRLF line, \r?$              b\r      b\r      -     b\r      b        b\r      b\r      b\r
dot across lines             a\nb\nc  a\nb\nc  -     -        a\nb\nc  a\nb\nc  a\nb\nc  a\nb\nc
dot across lines, Ruby (?m)  no       no       -     a\nb\nc  no       no       no       no
\R for any line break        -        a\r\nb   no    a\r\nb   a\r\nb   -        -        -
first line only              first    first    no    first    first    first    first    first
last line only               -        second   no    second   second   second   second   second
last line, Python's \Z       second   second   no    second   second   -        -        second

Reading the table

  • Rows 1–3, line anchors. ^b$ in a\nb\nc finds the middle line only in Ruby without a flag; with (?m) — or JavaScript's m flag — in everyone. Eight engines, one feature, two spellings and one default.
  • Rows 4–5, CRLF. The same (?m)^b$ on a\r\nb\r\nc matches only in Java: its $ recognises \r\n as a line ending. The other six treat the \r as the last character of the line, so b$ fails. Adding \r?$ — row 5 — makes them match, and the match then contains the \r (b\r), which is now in whatever you extract. Java, having handled it properly, returns b. JavaScript is - on both rows only because it has no (?m); the flags lesson passes the flag and shows it agreeing with Java.
  • Rows 6–7, dot. (?s)a.*c crosses the lines in six engines; Ruby refuses (?s). Ruby's spelling is (?m), row 7, and in the other six (?m) does nothing for the dot.
  • Row 8, \R. The one escape that matches \n, \r, \r\n (and the other Unicode line separators) as one unit: Perl, Ruby and Java. Elsewhere, \r?\n for CRLF-or-LF, and accept that a lone \r is not covered.
  • Rows 9–11, the first and last line. \A[^\n]* takes the first line in seven engines; JavaScript matched nothing because \A is the letter A there — ^ without m is its spelling. [^\n]*\z takes the last line where \z exists, and Python 3.12's spelling is \Z (row 11), which Go and Rust refuse.

The idioms

Job Portable pattern Notes
One line at a time split the text on \r?\n first, then match each line with no flags the only shape that is identical in all eight engines
A line that starts with ERROR (?m)^ERROR\b m flag in JavaScript; nothing in Ruby
Everything between two markers, across lines (?s)BEGIN(.*?)END (?m) in Ruby; [\s\S]*? in JavaScript when the flag is out of reach
Trailing whitespace on any line, CRLF-safe (?m)[ \t]+(?=\r?$) the lookahead keeps the \r out of the match
Normalise line endings first replace \R (or \r\n?) with \n after which every question above has one answer

Keywords on this page

^ · $ · \A \z \Z · . · Inline flags · Shorthand classes — for \R · (*CRLF).

See also