Start Debugging

RegexOptions.AnyNewLine chega no .NET 11 Preview 3: anchors Unicode-aware sem os hacks de \r?

.NET 11 Preview 3 adiciona RegexOptions.AnyNewLine para que ^, $, \Z, e . reconheçam toda sequência de newline Unicode, incluindo \r\n, NEL, LS, e PS, com \r\n tratado como um break atômico.

Se você já escreveu um regex multilinha em .NET e apelou pra \r?$ pra ficar seguro entre arquivos Windows e Unix, o workaround finalmente sai de cena. O .NET 11 Preview 3 introduz RegexOptions.AnyNewLine, que ensina ao engine o conjunto completo de terminadores de linha Unicode sem te forçar a soletrar cada um na mão.

A opção foi pedida lá no issue dotnet/runtime 25598 e saiu com o drop do Preview 3 em 14 de abril de 2026. Detalhes estão no anúncio do .NET 11 Preview 3.

O que a opção de fato muda

Com RegexOptions.AnyNewLine setado, os anchors ^, $, e \Z, mais . quando Singleline não está ativo, reconhecem toda sequência comum de newline definida pelo Unicode TR18 RL1.6:

Crucialmente, \r\n é tratado como uma sequência atômica. Isso significa que ^ não vai disparar entre o \r e o \n, e . não consome só o \r deixando o \n pendurado. Esse comportamento sozinho apaga uma classe de bugs cross-platform que parsers regex-heavy carregam há anos.

Antes vs depois

Imagine que você quer cada linha não-vazia de um arquivo misto editado no Windows, depois Linux, e depois passado por uma ferramenta Mac antiga. No .NET 10 você compensa por cada sabor de newline:

// .NET 10 style: opt in to every flavor manually
var legacy = new Regex(
    @"^(?<line>.+?)(?:\r?\n|\u2028|\u2029|\u0085|\z)",
    RegexOptions.Multiline);

No .NET 11 Preview 3 a mesma intenção comprime pra:

using System.Text.RegularExpressions;

var modern = new Regex(
    @"^(?<line>.+)$",
    RegexOptions.Multiline | RegexOptions.AnyNewLine);

string input = "first\r\nsecond\nthird\u2028fourth\u2029fifth\u0085sixth";

foreach (Match m in modern.Matches(input))
{
    Console.WriteLine(m.Groups["line"].Value);
}

Toda linha imprime limpa, sem compensação manual, e \r nunca vaza pro grupo capturado em input do Windows.

Com o que ele se recusa a combinar

Duas combinações são rejeitadas na hora da construção. Ambas lançam ArgumentOutOfRangeException:

// Both throw at construction
new Regex(@"^line$",
    RegexOptions.AnyNewLine | RegexOptions.NonBacktracking);

new Regex(@"^line$",
    RegexOptions.AnyNewLine | RegexOptions.ECMAScript);

O engine NonBacktracking assa o próprio modelo de newline no DFA, e o sabor ECMAScript está intencionalmente travado na semântica ECMA-262. Deixar qualquer um dos dois herdar silenciosamente o conjunto Unicode mudaria o comportamento de matching de formas que os callers não conseguem detectar facilmente, então o runtime falha alto na construção em vez de produzir matches surpreendentes em runtime.

RegexOptions.Singleline é a combinação amigável. Com ambos Singleline e AnyNewLine setados, . matcha todo caractere incluindo newlines, e ^, $, e \Z mantêm o comportamento completo de anchor Unicode.

Por que isso importa pra parsers de log e conteúdo

A maioria dos shims caseiros \r?\n em codebases .NET existe porque o comportamento padrão do regex trata só \n como quebra de linha. Logs, CSVs, headers RFC 822, e conteúdo colado de terminais todos batem nisso assim que um \r\n ou um \u2028 perdido aparece. Todo split defensivo, todo check “isso é um arquivo Windows”, todo off-by-one quando um separador Unicode entra no buffer, vem pagando esse imposto.

RegexOptions.AnyNewLine é uma API pequena, mas remove uma fonte de longa data de bugs regex cross-platform. Se você mantém um parser, log shipper, ou text indexer em .NET, o Preview 3 é a release onde você pode finalmente começar a podar esses workarounds.

< Voltar