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

Core dispute: What $ means

  • Thread centers on the fact that in many engines $ in non‑multiline mode matches either end-of-string or just before a trailing \n, not strictly “end-of-string.”
  • Some engines (JS, Go, Rust, RE2-style) make $ equivalent to “end of string” when multiline is off.
  • Others (Python, Java, C#, PHP, Perl, PCRE, etc.) treat $ more like “end of line,” with a special case for a single trailing newline.
  • Several commenters find the Python/Perl-style behavior surprising and “whacky,” especially examples like cat$ not matching cat\n\n.

Line vs string semantics

  • Big subthread argues whether $ is conceptually “end of line” or “end of string.”
  • One side insists the historical, line-based view (from editors, ed/sed/grep) justifies $ treating a trailing newline specially.
  • The other side counters that most APIs take arbitrary strings, not lines, so users reasonably expect $ to mean “end of string.”
  • There is debate over POSIX definitions of “line,” “incomplete line,” and how newline as terminator vs separator should affect $.

Regex dialects and (lack of) standardization

  • Many note there is no single regex standard; there are multiple families:
    • POSIX BRE/ERE, with different anchor semantics.
    • Perl/PCRE and descendants (PHP, many languages, PCRE2).
    • RE2-style, used by Go and Rust’s regex crate, which deliberately avoid some Perl quirks.
    • JavaScript’s ECMA regex, with its own gaps and features.
  • C++ <regex>, ECMA-262, POSIX, and a recent RFC (I-Regexp) are mentioned as formal specs, but they coexist rather than unify behavior.

Security and correctness implications

  • $ matching before a trailing newline has led to real bugs, e.g., in Ruby input validation and ExifTool/GitLab vulnerabilities, where attackers smuggle payloads after a newline.
  • Recommendation in several comments: when you truly mean “whole string,” use \A...\Z or \z where available, not ^...$.

Tooling, usage patterns, and ergonomics

  • Many advise always checking the specific engine’s docs and testing regexes explicitly.
  • Some prefer line-oriented tools (grep/sed/awk, editors like Vim) and think in terms of lines; others primarily work with in-memory strings and expect string semantics.
  • Broader frustration appears around regex flavor fragmentation, escaping rules, and inconsistent support for character classes and anchors.