¿Cómo usar [\ w] + en expresión regular en sed?


24

Estoy en Windows, pero supongo que mi pregunta aún se encuentra aquí.

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

Noté que los siguientes trabajos (salida here):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

Pero esto no funciona (sin generar nada):

echo here | grep -E "[\w]+"

Esto nuevamente hace (salida here):

echo here | grep -P "[\w]+"

Entonces [\w], supongo que es algo específico de las expresiones regulares de Perl. ¿Es eso correcto?

Entonces, hablemos sed. Esto funciona (salida gone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

Y de nuevo, esto no (salida here):

echo here | sed -r "s/[\w]+/gone/"

Ahora, ¿cómo puedo activar las expresiones regulares de Perl para sed? ¿Hay alguna manera?

Respuestas:


11

Las diferentes herramientas y versiones de las mismas admiten diferentes variantes de expresiones regulares. La documentación de cada uno le dirá qué respaldan.

Existen estándares para que uno pueda confiar en un conjunto mínimo de características que están disponibles en todas las aplicaciones conformes.

Por ejemplo, todas las implementaciones modernas sede grepimplementan expresiones regulares básicas según lo especificado por POSIX (al menos una versión u otra del estándar, pero ese estándar no ha evolucionado mucho en ese sentido en las últimas décadas).

En POSIX BRE y ERE, tienes la [:alnum:]clase de personaje. Eso coincide con letras y dígitos en su configuración regional (tenga en cuenta que a menudo incluye mucho más que a a-zA-Z0-9menos que la configuración regional sea C).

Asi que:

grep -x '[[:alnum:]_]\{1,\}'

coincide con uno o más alnums o _.

[\w]POSIX requiere que coincida con la barra diagonal inversa o w. Por lo que no encontrará una grepo sedaplicación que está disponible en (a no ser a través de las opciones no estándar).

\wPOSIX no especifica el comportamiento solo, por lo que las implementaciones pueden hacer lo que quieran. GNU grepagregó eso hace mucho tiempo.

GNU grepsolía tener su propio motor regexp, sin embargo, ahora usa el de GNU libc (aunque incorpora su propia copia).

Está destinado a combinar alnums y guiones bajos en su entorno local. Sin embargo, actualmente tiene un error, ya que solo coincide con caracteres de un solo byte (por ejemplo, no é en una configuración regional UTF-8 a pesar de que es claramente una letra y aunque coincide con é en todas las configuraciones regionales donde é es una sola personaje).

También hay un \woperador regexp en perl regexp y en PCRE. PCRE / perl no son expresiones regulares POSIX, son simplemente otra cosa.

Ahora, con la forma en que GNU grep -Pusa PCRE, tiene el mismo problema que sin él -P. Sin embargo, se puede solucionar allí usando (*UCP)(aunque eso también tiene efectos secundarios en entornos locales que no son UTF8).

GNU sedtambién usa las expresiones regulares libc de GNU para sus propias expresiones regulares. Sin embargo, lo usa de tal manera que no tiene el mismo error que GNU grep.

GNU sedno es compatible con PCRE. Hay algunas pruebas en el código de que se ha intentado antes, pero ya no parece estar en la agenda.

Si quieres las expresiones regulares de Perl, solo perlúsalas.

De lo contrario, diría que en lugar de tratar de confiar en una característica no estándar falsa de su implementación particular de sed/ grep, sería mejor seguir con el estándar y el uso [_[:alnum:]].


[_[:alnum:]]es una buena solución que me permite extenderla como [\w/]( [_[:alnum:]/]en ese caso).
Bers

1
Esta respuesta ahora está desactualizada con respecto a las limitaciones de GNU grep.
Stéphane Chazelas

7

Tienes razón, \wes parte de PCRE, expresiones regulares compatibles con Perl. Sin embargo, no es parte de la expresión regular 'estándar'. http://www.regular-expressions.info/posix.html

Algunas versiones de sedpueden admitirlo, pero sugeriría que la forma más fácil es usarlo perlen sedmodo especificando la -pbandera. (Junto con el -e). (Más detalles en perlrun)

Pero []en ese ejemplo, no necesitas evitarlo, eso es para grupos de cosas válidas.

echo here  | perl -pe 's/\w+/gone/'

O en Windows:

C:\>echo here  | perl -pe "s/\w+/gone/"
gone
C:\>echo here  | perl -pe "s/[\w\/]+/gone/"
gone

Ver perlrepara más cosas PCRE.

Puede obtener perl aquí: http://www.activestate.com/activeperl/downloads


Tenga en cuenta la diferencia entre \wy [\w]en mi pregunta. Lo actualizaré con las salidas de cada comando para dejar en claro cuál funciona y cuál no. En particular, sedentiende \w, pero no [\w]. Además, necesito [\w]trabajar porque quiero usar, [\w/]por ejemplo.
Bers

En cuyo caso, probablemente sea un problema de cotización. De cualquier manera, perlpuede hacerlo :).
Sobrique

¡Gracias! La respuesta de Stéphane Chazelas está un poco más cerca de lo que pedí (ya que no tengo instalado Perl, un usuario du * b de Windows, supongo), así que acepté su respuesta.
Bers

Eso está bien, pero recomendaría instalar Perl en Windows. Es una de las primeras cosas que pasa en la mía, y me resulta extremadamente útil.
Sobrique

\westaba en GNU grep (en los años 80) antes de estar en perl y en GNU emacs probablemente incluso antes de eso.
Stéphane Chazelas

1

Sospecho que grepy estoy seddecidiendo de manera diferente cuándo aplicar el []y cuándo expandir el \w. En perl, regex \wsignifica cualquier carácter de palabra, y []define un grupo para aplicar cualquiera de los caracteres dentro de una coincidencia. Si "expande" \wantes del [], será una clase de caracteres de todas las palabras. Si, en cambio lo hace []primero que tendrá una clase de carácter con dos personajes \y wpor lo que se correspondería con cualquier patrón que contiene uno o más de esos dos personajes.

Entonces parece que sedes ver []y tratarlo como si contuviera los caracteres exactos para que coincidan en lugar de honrar la secuencia especial \wcomo perly lo grephacen. Por supuesto, []son completamente innecesarios en este ejemplo, pero uno podría imaginar casos en los que sería importante, pero luego podría hacer que funcione con parens y ors.


Me sorprendería si fuera así. \ es un código de escape, y lo usarías para delimitadores de escape. Inherentemente, eso significa que tiene que tener una precedencia más alta que cualquier otra cosa. Creo que es más probable que no se implemente porque \wno es parte de la especificación de expresión regular
Sobrique

Bueno, empíricamente parece ser el caso usando gnu sed para mí: me echo whe\\ere | sed -r 's/[\w]+/gone/gda gonehegoneerecomo si ` and estuviera haciendo coincidir cada una de las w` y haciendo la sustitución
Eric Renouf

Puedo confirmar lo que Eric Renouf está viendo. Entonces, ¿queremos eliminar la barra invertida de alguna manera? :)
bers

No creo que sea la respuesta correcta. Sed simplemente no admite mezclar los diferentes tipos de definiciones de clases de caracteres, por lo que la respuesta es si debe usar ambos tipos de clases de caracteres, elija otra herramienta, o si está eligiendo sed, use la sintaxis que admite
Eric Renouf,
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.