Coincidir con espacios en blanco pero no con nuevas líneas
A veces quiero hacer coincidir los espacios en blanco pero no la nueva línea.
Hasta ahora he estado recurriendo a [ \t]
. ¿Existe una forma menos incómoda?
Resumen
- Úselo
\h
para hacer coincidir espacios en blanco horizontales, en Perl desde v5.10.0 (lanzado en 2007) - Para motores que no sean PCRE , utilice un doble negativo:
[^\S\r\n]
- Propiedades Unicode:
\p{Blank}
o\p{HorizSpace}
- Sea directo, en ASCII:
[\t\f\cK ]
- Sea directo, en Unicode (pero no lo haga, en realidad)
- Otras aplicaciones de dobles negativos y propiedades Unicode
Espacios en blanco horizontales
La sección "Clases de personajes y otros escapes especiales" de perlre incluye
\h
espacios en blanco horizontales\H
No espacios en blanco horizontales
Doble negativa
Si puede utilizar su patrón con otros motores, particularmente aquellos que no son compatibles con Perl o que no admiten \h
, expréselo como un doble negativo:
[^\S\r\n]
Es decir, no-no-espacios en blanco (los S
complementos mayúsculas) o no-retorno-de-carro o no-nueva línea. Distribuir el not externo ( es decir , el complemento ^
en la clase de caracteres entre corchetes ) con la ley de De Morgan , esto equivale a restar \r
y \n
de \s
. La inclusión de retorno de carro y nueva línea en el patrón maneja correctamente todas las convenciones de nueva línea de Unix (LF), Mac OS clásico (CR) y DOS-ish (CRLF) .
No es necesario que confíes en mi palabra:
#! /usr/bin/env perl
use strict;
use warnings;
my $ws_not_crlf = qr/[^\S\r\n]/;
for (' ', '\f', '\t', '\r', '\n') {
my $qq = qq["$_"];
printf "%-4s => %s\n", $qq,
(eval $qq) =~ $ws_not_crlf ? "match" : "no match";
}
Producción:
" " => coincidencia "\f" => coincidencia "\t" => coincidencia "\r" => no coincide "\n" => no coincide
Tenga en cuenta la exclusión de la pestaña vertical, pero esto se aborda en v5.18 .
Antes de objetar demasiado duramente, la documentación de Perl utiliza la misma técnica. Una nota a pie de página en la sección "Espacio en blanco" de perlrecharclass dice
Antes de Perl v5.18,
\s
no coincidía con la pestaña vertical.[^\S\cK]
(oscuramente) coincide con lo que\s
tradicionalmente se hacía.
Propiedades Unicode
La documentación de Perlre antes mencionada \h
hace\H
referencia a la documentación de Perlunicode donde leemos sobre una familia de propiedades Unicode útiles.
\p{Blank}
- Esto es lo mismo que
\h
y\p{HorizSpace}
: un carácter que cambia el espaciado horizontalmente.\p{HorizSpace}
- Esto es lo mismo que
\h
y\p{Blank}
: un carácter que cambia el espaciado horizontalmente.
El enfoque directo: edición ASCII
La sección "Espacio en blanco" de perlrecharclass también sugiere otros enfoques que no ofenderán la oposición de los profesores de gramática a los dobles negativos.
Di lo que quieres en lugar de lo que no quieres.
Fuera de las reglas locales y Unicode o cuando el modificador /a
o/aa
está en vigor, " \s
coincide con [\t\n\f\r ]
y, a partir de Perl v5.18, la pestaña vertical \cK
".
Para hacer coincidir los espacios en blanco pero no las nuevas líneas (en sentido amplio), descarte \r
y \n
salga
[\t\f\cK ]
El enfoque directo: edición Unicode
Si su texto es Unicode, use un código similar al siguiente para construir un patrón a partir de la tabla en la sección "Espacio en blanco" de perlrecharclass .
sub ws_not_nl {
local($_) = <<'EOTable';
0x0009 CHARACTER TABULATION h s
0x000a LINE FEED (LF) vs
0x000b LINE TABULATION vs [1]
0x000c FORM FEED (FF) vs
0x000d CARRIAGE RETURN (CR) vs
0x0020 SPACE h s
0x0085 NEXT LINE (NEL) vs [2]
0x00a0 NO-BREAK SPACE h s [2]
0x1680 OGHAM SPACE MARK h s
0x2000 EN QUAD h s
0x2001 EM QUAD h s
0x2002 EN SPACE h s
0x2003 EM SPACE h s
0x2004 THREE-PER-EM SPACE h s
0x2005 FOUR-PER-EM SPACE h s
0x2006 SIX-PER-EM SPACE h s
0x2007 FIGURE SPACE h s
0x2008 PUNCTUATION SPACE h s
0x2009 THIN SPACE h s
0x200a HAIR SPACE h s
0x2028 LINE SEPARATOR vs
0x2029 PARAGRAPH SEPARATOR vs
0x202f NARROW NO-BREAK SPACE h s
0x205f MEDIUM MATHEMATICAL SPACE h s
0x3000 IDEOGRAPHIC SPACE h s
EOTable
my $class;
while (/^0x([0-9a-f]{4})\s+([A-Z\s]+)/mg) {
my($hex,$name) = ($1,$2);
next if $name =~ /\b(?:CR|NL|NEL|SEPARATOR)\b/;
$class .= "\\N{U+$hex}";
}
qr/[$class]/u;
}
Lo anterior es para completar. Utilice las propiedades Unicode en lugar de escribirlas a mano.
Otras aplicaciones
El truco del doble negativo también es útil para hacer coincidir caracteres alfabéticos. Recuerde que \w
coincide con "caracteres de palabras", caracteres alfabéticos y dígitos y guión bajo. Nosotros, los feos estadounidenses, a veces queremos escribirlo como, digamos,
if (/[A-Za-z]+/) { ... }
pero una clase de carácter doble negativo puede respetar la configuración regional:
if (/[^\W\d_]+/) { ... }
Expresar “un carácter de palabra pero no un dígito ni un guión bajo” de esta manera es un poco opaco. Una clase de caracteres POSIX comunica la intención de forma más directa
if (/[[:alpha:]]+/) { ... }
o con una propiedad Unicode como sugirió szbalint
if (/\p{Letter}+/) { ... }
Pingui preguntó acerca de anidar la clase de carácter doble negativo para modificar efectivamente \s
el
/(\+|0|\()[\d()\s-]{6,20}\d/g
Lo mejor que se me ocurrió es utilizar |
una alternativa y moverla \s
a la otra rama:
/(\+|0|\()(?:[\d()-]|[^\S\r\n]){6,20}\d/g
Las versiones de Perl 5.10 y posteriores admiten clases de caracteres verticales y horizontales subsidiarias, \v
así \h
como la clase genérica de caracteres de espacios en blanco.\s
La solución más limpia es utilizar la clase de carácter de espacio en blanco horizontal\h
. Esto coincidirá con la tabulación y el espacio del conjunto ASCII, el espacio continuo del ASCII extendido o cualquiera de estos caracteres Unicode.
U+0009 CHARACTER TABULATION
U+0020 SPACE
U+00A0 NO-BREAK SPACE (not matched by \s)
U+1680 OGHAM SPACE MARK
U+2000 EN QUAD
U+2001 EM QUAD
U+2002 EN SPACE
U+2003 EM SPACE
U+2004 THREE-PER-EM SPACE
U+2005 FOUR-PER-EM SPACE
U+2006 SIX-PER-EM SPACE
U+2007 FIGURE SPACE
U+2008 PUNCTUATION SPACE
U+2009 THIN SPACE
U+200A HAIR SPACE
U+202F NARROW NO-BREAK SPACE
U+205F MEDIUM MATHEMATICAL SPACE
U+3000 IDEOGRAPHIC SPACE
El patrón de espacio vertical\v
es menos útil, pero coincide con estos caracteres.
U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0085 NEXT LINE (not matched by \s)
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR
Hay siete caracteres de espacios en blanco verticales que coinciden \v
y dieciocho caracteres horizontales que coinciden \h
. \s
coincide con veintitrés caracteres
Todos los caracteres de espacio en blanco son verticales u horizontales sin superposición, pero no son subconjuntos adecuados porque \h
también coinciden con U+00A0 ESPACIO SIN INTERRUPCIÓN y \v
también coinciden con U+0085 NEXT LINE, ninguno de los cuales coincide con\s
Una variación de la respuesta de Greg que también incluye retornos de carro:
/[^\S\r\n]/
Esta expresión regular es más segura que /[^\S\n]/
sin \r
. Mi razonamiento es que Windows usa \r\n
nuevas líneas y Mac OS 9 usa \r
. \r
Es poco probable que lo encuentres \n
hoy en día, pero si lo encuentras, no podría significar nada más que una nueva línea. Por lo tanto, dado que \r
puede significar una nueva línea, también deberíamos excluirla.
La siguiente expresión regular coincidiría con espacios en blanco pero no con un carácter de nueva línea.
(?:(?!\n)\s)
MANIFESTACIÓN
Si también desea agregar retorno de carro, agregue \r
con el |
operador dentro de la anticipación negativa.
(?:(?![\n\r])\s)
MANIFESTACIÓN
Agregue +
después del grupo que no captura para que coincida con uno o más espacios en blanco.
(?:(?![\n\r])\s)+
MANIFESTACIÓN
No sé por qué no mencionaron la clase de caracteres POSIX [[:blank:]]
que coincide con los espacios en blanco horizontales ( espacios y tabulaciones ). Esta clase de caracteres POSIX funcionaría en BRE ( expresiones regulares básicas ), ERE ( expresión regular extendida ), PCRE ( expresión regular compatible con Perl ).
MANIFESTACIÓN
Lo que buscas es la blank
clase de caracteres POSIX. En Perl se hace referencia a él como:
[[:blank:]]
en Java (no olvide habilitar UNICODE_CHARACTER_CLASS
):
\p{Blank}
En comparación con similares \h
, POSIX blank
es compatible con algunos motores de expresiones regulares más ( referencia ). Un beneficio importante es que su definición está fijada en el Anexo C: Propiedades de compatibilidad de expresiones regulares Unicode y estándar en todos los tipos de expresiones regulares que admiten Unicode. (En Perl, por ejemplo, \h
elige incluir adicionalmente el MONGOLIAN VOWEL SEPARATOR
.) Sin embargo, un argumento a favor de \h
es que siempre detecta caracteres Unicode (incluso si los motores no se ponen de acuerdo sobre cuáles), mientras que las clases de caracteres POSIX suelen ser ASCII por defecto. -solo (como en Java).
Pero el problema es que ni siquiera seguir Unicode resuelve el problema al 100%. Considere los siguientes caracteres que no se consideran espacios en blanco en Unicode:
U+180E SEPARADOR DE VOCALES MONGOLIANAS
U+200B ESPACIO ANCHO CERO
U+200C ANCHO CERO NO EMBALAJE
CARPINTERÍA ANCHO CERO U+200D
U+2060 UNIÓN DE PALABRAS
U+FEFF ANCHO CERO ESPACIO IRRPONIBLE
Tomado de https://en.wikipedia.org/wiki/White-space_character
El separador de vocales mongol antes mencionado no se incluye por lo que probablemente sea una buena razón. Este, junto con 200C y 200D, ocurre dentro de palabras (AFAIK) y, por lo tanto, rompe la regla fundamental que obedecen todos los demás espacios en blanco: puedes tokenizar con él. Son más como modificadores. Sin embargo, ZERO WIDTH SPACE
, WORD JOINER
y ZERO WIDTH NON-BREAKING SPACE
(si se usa como algo distinto a una marca de orden de bytes) se ajustan a la regla de espacios en blanco de mi libro. Por lo tanto, los incluyo en mi clase de caracteres de espacios en blanco horizontales.
En Java:
static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"