regex - tabla - expresion regular espacio en blanco
¿Cómo emular el límite de palabras cuando se usan propiedades de caracteres Unicode? (2)
Deberías estar usando lookarounds negativos:
(?<!/p{Word})(/p{Word}+)(?!/p{Word})
Las alternativas positivas fallan al inicio o al final de la cadena porque requieren que esté presente un carácter sin palabras. Las correcciones negativas funcionan en ambos casos.
De mis preguntas anteriores ¿ Por qué los caracteres de palabras de locale-pragma no coinciden? y Cómo cambiar las comillas anidadas Aprendí que cuando se trata de datos UTF-8 no se puede confiar en /w
como word-char y se debe usar la propiedad de caracteres Unicode /p{Word}
. Ahora estoy en una situación en la que descubrí que el límite de palabras de ancho cero /b
tampoco funciona con UTF-8 (con configuración local habilitada), pero no encontré ningún equivalente en las propiedades de caracteres Unicode. Pensé que podría construirlo yo mismo como: (?<=/P{Word})(/p{Word}+)(?=/P{Word})
, debería ser equivalente a /b(/w+)/b
.
En el script de prueba a continuación, tengo dos matrices para probar dos expresiones regulares diferentes. El primero basado en /b
funciona bien cuando la configuración regional no está habilitada. Para que también funcione con configuraciones regionales, escribí otra versión con emulación de límite (?=/P{Word})
pero no funciona como esperaba (también se muestran los resultados esperados en el script).
¿Ves lo que está mal y cómo obtener la expresión regular emulada como primero con ASCII (o sin configuración regional)?
#!/usr/bin/perl
use 5.010;
use utf8::all;
use locale; # et_EE.UTF-8 in my case
$| = 1;
my @test_boundary = ( # EXPECTED RESULT:
''"abc def"'', # ''«abc def»''
''"abc "d e f" ghi"'', # ''«abc «d e f» ghi»''
''"abc "d e f""'', # ''«abc «d e f»»''
''"abc "d e f"'', # ''«abc "d e f»''
''"abc "d" "e" f"'', # ''«abc «d» «e» f»''
# below won''t work with /b when locale enabled
''"100 Естонiï"'', # ''«100 Естонiï»''
''"äöõ "ä õ ü" ï"'', # ''«äöõ «ä õ ü» ï»''
''"äöõ "ä õ ü""'', # ''«äöõ «ä õ ü»»''
''"äöõ "ä õ ü"'', # ''«äöõ «ä õ ü»''
''"äöõ "ä" "õ" ï"'', # ''«äöõ «ä» «õ» ï»''
);
my @test_emulate = ( # EXPECTED RESULT:
''"100 Естонiï"'', # ''«100 Естонiï»''
''"äöõ "ä õ ü" ï"'', # ''«äöõ «ä õ ü» ï»''
''"äöõ "ä õ ü""'', # ''«äöõ «ä õ ü»»''
''"äöõ "ä õ ü"'', # ''«äöõ "ä õ ü»''
''"äöõ "ä" "õ" ï"'', # ''«äöõ «ä» «õ» ï»''
);
say "BOUNDARY";
for my $sentence ( @test_boundary ) {
my $quote_count = ( $sentence =~ tr/"/"/ );
for ( my $i = 0 ; $i <= $quote_count ; $i += 2 ) {
$sentence =~ s/
"( # first qoute, start capture
[/p{Word}/.]+? # suva word-char
.*?/b[/.,?!»]*? # any char followed boundary + opt. punctuation
)" # stop capture, ending quote
/«$1»/xg; # change to fancy
}
say $sentence;
}
say "EMULATE";
for my $sentence ( @test_emulate ) {
my $quote_count = ( $sentence =~ tr/"/"/ );
for ( my $i = 0 ; $i <= $quote_count ; $i += 2 ) {
$sentence =~ s/
"( # first qoute, start capture
[/p{Word}/.]+? # at least one word-char or point
.*?(?=/P{Word}) # any char followed boundary
[/.,?!»]*? # optional punctuation
)" # stop capture, ending quote
/«$1»/gx; # change to fancy
}
say $sentence;
}
Dado que el carácter después de la posición de la /b
es una puntuación o "
(para estar seguro, compruebe que /p{Word}
no coincide con ninguno de ellos), cae en el caso /b/W
Por lo tanto, podemos emular /b
con:
(?<=/p{Word})
No estoy familiarizado con Perl, pero por lo que probé aquí , parece que /w
(y /b
) también funciona bien cuando la codificación está configurada en UTF-8.
$sentence =~ s/
"(
[/w/.]+?
.*?/b[/.,?!»]*?
)"
/«$1»/xg;
Si asciende a Perl 5.14 y superior, puede establecer el juego de caracteres en Unicode con u
flag.
Puede usar esta estrategia general para construir un límite correspondiente a una clase de caracteres. (Al igual que cómo /b
definición de límite de palabras se basa en la definición de /w
).
Deje que C
sea la clase de personaje. Nos gustaría definir un límite que se base en la clase de caracteres C.
La construcción siguiente emulará los límites al frente cuando sepa que el carácter actual pertenece a la clase de caracteres C
(equivalente a (/b/w)
):
(?<!C)C
O detrás (equivalente a /w/b
):
C(?!C)
¿Por qué look-around negativo? Debido a que la observación positiva (con la clase de caracteres complementarios) también afirmará que debe haber un personaje adelante / atrás (afirmar el ancho adelante / atrás al menos 1). La revisión negativa permitirá el caso de inicio / finalización de la cadena sin escribir una expresión regular engorrosa.
Para la emulación /B/w
:
(?<=C)C
y similarmente /w/B
:
C(?=C)
/B
es el opuesto directo de /b
, por lo tanto, podemos voltear el aspecto positivo / negativo para emular el efecto. También tiene sentido: un límite no solo se puede formar cuando hay más personajes adelante / atrás.
Otras emulaciones ( c
sea la clase de caracteres complementarios de C
):
-
/b/W
:(?<=C)c
-
/W/b
:c(?=C)
-
/B/W
:(?<!C)c
-
/W/B
:c(?!C)
Para la emulación de un límite independiente (equivalente a /b
):
(?:(?<!C)(?=C)|(?<=C)(?!C))
Y sin límite independiente (equivalente a /B
):
(?:(?<!C)(?!C)|(?<=C)(?=C))