Tengo varios archivos XML muy grandes y estoy tratando de encontrar las líneas que contienen caracteres no ASCII. He intentado lo siguiente:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
Pero esto devuelve todas las líneas del archivo, independientemente de si la línea contiene un carácter en el rango especificado.
¿Tengo la sintaxis incorrecta o estoy haciendo algo más mal? También he intentado:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(con comillas simples y dobles que rodean el patrón).
Respuestas:
Puedes usar el comando:
Esto le dará el número de línea y resaltará los caracteres no ascii en rojo.
En algunos sistemas, dependiendo de su configuración, lo anterior no funcionará, por lo que puede grep por el inverso
Tenga en cuenta también que el bit importante es la
-P
bandera que equivale a--perl-regexp
: por lo que interpretará su patrón como una expresión regular de Perl. También dice quefuente
grep
(en OS X 10.8 Mountain Lion), ya que no admite laP
opción.grep
está disponible en ladupes
biblioteca de Homebrew (habilitar usandobrew tap homebrew/dupes
):brew install grep
dupes
biblioteca es instalar en supcre
lugar:brew install pcre
... como parte de esto, obtendrá lapcregrep
utilidad, que puede usar de la siguiente manera:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
brew
usuarios de Mac , se pueden instalar los coreutils de GNUbrew install coreutils
. Esto le dará muchas herramientas GNU con el prefijo 'g', en este caso, useggrep
. Esto debería evitar los problemas derivados de la sustitución de una utilidad del sistema, ya que los scripts Mac específicos del sistema ahora dependen de BSD grep.ag "[\x80-\xFF]" file
que solo necesita instalarthe_silver_searcher
En lugar de hacer suposiciones sobre el rango de bytes de caracteres no ASCII, como lo hacen la mayoría de las soluciones anteriores, es un poco mejor IMO ser explícito sobre el rango de bytes real de caracteres ASCII.
Entonces, la primera solución, por ejemplo, sería:
(que básicamente greps para cualquier carácter fuera del rango hexadecimal ASCII: desde \ x00 hasta \ x7F)
En Mountain Lion eso no funcionará (debido a la falta de soporte PCRE en BSD grep) , pero con
pcre
instalado a través de Homebrew, lo siguiente funcionará igual de bien:¿Algún pros o contras que alguien pueda pensar?
fuente
LC_COLLATE=C grep $'[^\1-\177]'
funciona (para archivos sin bytes nulos)Lo siguiente funciona para mí:
Los caracteres no ASCII comienzan en 0x80 y van a 0xFF cuando se miran los bytes. Grep (y su familia) no realizan el procesamiento Unicode para fusionar caracteres de varios bytes en una sola entidad para la coincidencia de expresiones regulares como parece querer. La
-P
opción en mi grep permite el uso de\xdd
escapes en las clases de personajes para lograr lo que quieres.fuente
echo '소녀시대' | grep -P "[\x80-\xFF]"
no me devuelve nada, ¿alguien más puede confirmarlo? (GNU grep 2.21)echo '소녀시대' | grep -P "[^\x00-\x7F]"
. O simplemente usethe_silver_searcher
según lo indicado por @slf:echo '소녀시대' | ag "[\x80-\xFF]"
En perl
fuente
perl -lne 'print if /[^[:ascii:]]/' file.xml
La manera fácil es definir un carácter no ASCII ... como un carácter que no es un carácter ASCII.
Agregue una pestaña después de
^
si es necesario.La configuración
LC_COLLATE=C
evita sorpresas desagradables sobre el significado de los rangos de caracteres en muchos entornos locales. La configuraciónLC_CTYPE=C
es necesaria para que coincidan los caracteres de un solo byte; de lo contrario, el comando perdería secuencias de bytes no válidas en la codificación actual. La configuraciónLC_ALL=C
evita los efectos locales dependientes por completo.fuente
echo "A" | LC_COLLATE=C grep '[^ -~]'
devuelve un partidoLC_ALL=en_US.UTF-8
, eso triunfa sobre laLC_COLLATE
configuración. ¡No deberías tener esto en tu entorno!LC_ALL
es solo para forzar a una tarea específica a usar una configuración regional particular, por lo generalC
. Para establecer la configuración regional predeterminada para todas las categorías, establezcaLANG
.LC_ALL=C
, se comporta de manera diferente en Mac OS X y Ubuntu. Después de agregar esta configuración, dan el mismo resultado.Aquí hay otra variante que encontré que produjo resultados completamente diferentes de la búsqueda grep
[\x80-\xFF]
en la respuesta aceptada. Quizás sea útil para alguien encontrar caracteres adicionales que no sean ascii:grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Nota: el grep de mi computadora (una Mac) no tenía
-P
opción, así que lo hicebrew install grep
y comencé la llamada anterior con enggrep
lugar degrep
.fuente
El siguiente código funciona:
Reemplácelo
/tmp
con el nombre del directorio que desea buscar.fuente
Buscando caracteres no imprimibles. TLDR; Resumen Ejecutivo
LC_ALL=C
necesaria para que grep haga lo que podría esperar con unicode extendidoSO los buscadores de caracteres no ascii preferidos:
como en la respuesta superior, el grep inverso:
como en la respuesta superior pero CON
LC_ALL=C
:. . más . . detalles insoportables sobre esto:. . .
Estoy de acuerdo con Harvey anteriormente enterrado en los comentarios, a menudo es más útil buscar caracteres no imprimibles O es fácil pensar no ASCII cuando realmente debería estar pensando no imprimible. Harvey sugiere "use esto:"
[^\n -~]
". Agregue \ r para archivos de texto de DOS. Eso se traduce en"[^\x0A\x020-\x07E]
"y agregue \ x0D para CR"Además, agregar -c (mostrar el recuento de patrones coincidentes) a grep es útil cuando se buscan caracteres no imprimibles, ya que las cadenas coincidentes pueden estropear el terminal.
Descubrí que agregar el rango 0-8 y 0x0e-0x1f (al rango 0x80-0xff) es un patrón útil. Esto excluye TAB, CR y LF y uno o dos caracteres imprimibles poco comunes más. Entonces, en mi humilde opinión, un patrón grep bastante útil (aunque crudo) es éste:
REALMENTE, generalmente necesitarás hacer esto:
Descompostura:
Ejemplo práctico de uso find para grep todos los archivos en el directorio actual:
Es posible que desee ajustar el grep a veces. por ejemplo, BS (0x08 - retroceso) char usado en algunos archivos imprimibles o para excluir VT (0x0B - pestaña vertical). Los caracteres BEL (0x07) y ESC (0x1B) también pueden considerarse imprimibles en algunos casos.
ACTUALIZACIÓN: tuve que volver a visitar esto recientemente. Y, YYMV dependiendo de la configuración del terminal / pronóstico del tiempo solar PERO. . Noté que grep no estaba encontrando muchos caracteres unicode o extendidos. Aunque intuitivamente deberían coincidir con el rango de 0x80 a 0xff, los caracteres unicode de 3 y 4 bytes no coincidían. ??? ¿Alguien puede explicar esto? SI. @frabjous preguntó y @calandoa explicó que
LC_ALL=C
debería usarse para establecer la configuración regional del comando para hacer coincidir grep.Por ejemplo, mi localidad
LC_ALL=
vacíagrep con
LC_ALL=
coincidencias vacías con caracteres de 2 bytes codificados pero no con 3 y 4 bytes codificados:grep with
LC_ALL=C
parece coincidir con todos los caracteres extendidos que desea:ESTA coincidencia perl (parcialmente encontrada en otro lugar en stackoverflow) O el grep inverso en la respuesta superior NO parece encontrar TODOS los caracteres "extraños" y ~ maravillosos ~ "no ascii" extraños sin establecer la configuración regional:
SO los buscadores de caracteres no ascii preferidos:
como en la respuesta superior, el grep inverso:
como en la respuesta superior pero CON
LC_ALL=C
:fuente
¡Extrañamente, tuve que hacer esto hoy! Terminé usando Perl porque no podía hacer que grep / egrep funcionara (incluso en modo -P). Algo como:
Para los caracteres unicode (como
\u2212
en el ejemplo a continuación) use esto:fuente
Puede ser interesante saber cómo buscar un carácter unicode. Este comando puede ayudar. Solo necesita saber el código en UTF8
fuente
Encontrar todos los caracteres que no son ascii da la impresión de que uno está buscando cadenas unicode o tiene la intención de quitar dichos caracteres individualmente.
Para el primero, pruebe uno de estos (la variable
file
se usa para la automatización):La vainilla grep no funciona correctamente sin LC_ALL = C como se señaló en las respuestas anteriores.
El rango ASCII es
x00-x7F
, el espacio esx20
, ya que las cadenas tienen espacios, el rango negativo lo omite.El rango no ASCII es
x80-xFF
, dado que las cadenas tienen espacios, el rango positivo lo agrega.Se supone que la cadena tiene al menos 7 caracteres consecutivos dentro del rango.
{7,}
.Para la salida legible por shell,
uchardet $file
devuelve una suposición de la codificación del archivo que se pasa a iconv para la interpolación automática.fuente
uchardet
comando. Gracias por ese aviso!