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
-Pbandera 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 laPopción.grepestá disponible en ladupesbiblioteca de Homebrew (habilitar usandobrew tap homebrew/dupes):brew install grepdupesbiblioteca es instalar en supcrelugar:brew install pcre... como parte de esto, obtendrá lapcregreputilidad, que puede usar de la siguiente manera:pcregrep --color='auto' -n "[\x80-\xFF]" file.xmlbrewusuarios 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]" fileque solo necesita instalarthe_silver_searcherEn 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
pcreinstalado 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
-Popción en mi grep permite el uso de\xddescapes 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_searchersegún lo indicado por @slf:echo '소녀시대' | ag "[\x80-\xFF]"En perl
fuente
perl -lne 'print if /[^[:ascii:]]/' file.xmlLa 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=Cevita sorpresas desagradables sobre el significado de los rangos de caracteres en muchos entornos locales. La configuraciónLC_CTYPE=Ces 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=Cevita 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_COLLATEconfiguración. ¡No deberías tener esto en tu entorno!LC_ALLes 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.txtNota: el grep de mi computadora (una Mac) no tenía
-Popción, así que lo hicebrew install grepy comencé la llamada anterior con enggreplugar degrep.fuente
El siguiente código funciona:
Reemplácelo
/tmpcon el nombre del directorio que desea buscar.fuente
Buscando caracteres no imprimibles. TLDR; Resumen Ejecutivo
LC_ALL=Cnecesaria 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=Cdeberí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=Cparece 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
\u2212en 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
filese 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 $filedevuelve una suposición de la codificación del archivo que se pasa a iconv para la interpolación automática.fuente
uchardetcomando. Gracias por ese aviso!