¿Cómo busco todos los caracteres que no son ASCII?
Tengo varios archivos XML muy grandes y estoy intentando encontrar las líneas que contienen caracteres que no son ASCII. Intenté lo siguiente:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
Pero esto devuelve cada línea del archivo, independientemente de si la línea contiene un carácter en el rango especificado.
¿Tengo mal la sintaxis o estoy haciendo algo más mal? También lo intenté:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(con comillas simples y dobles rodeando el patrón).
Puedes usar el comando:
grep --color='auto' -P -n "[\x80-\xFF]" file.xml
Esto le dará el número de línea y resaltará los caracteres que no sean ASCII en rojo.
En algunos sistemas, dependiendo de su configuración, lo anterior no funcionará, por lo que puede buscar a la inversa
grep --color='auto' -P -n "[^\x00-\x7F]" file.xml
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 que
Esto es altamente experimental y grep -P puede advertir sobre características no implementadas.
En lugar de hacer suposiciones sobre el rango de bytes de caracteres no ASCII, como lo hacen la mayoría de las soluciones anteriores, en mi opinión, es un poco mejor ser explícito sobre el rango de bytes real de caracteres ASCII.
Entonces la primera solución, por ejemplo, sería:
grep --color='auto' -P -n '[^\x00-\x7F]' file.xml
(que básicamente busca cualquier carácter fuera del rango ASCII hexadecimal: desde \x00 hasta \x7F)
En Mountain Lion eso no funcionará (debido a la falta de soporte PCRE en BSD grep) , pero si pcre
se instala a través de Homebrew, lo siguiente funcionará igual de bien:
pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml
¿Algún pros o contras que alguien pueda pensar?
La forma más sencilla es definir un carácter que no sea ASCII... como un carácter que no es un carácter ASCII.
LC_ALL=C grep '[^ -~]' file.xml
El código anterior busca caracteres que no son caracteres ASCII imprimibles: caracteres que no son ASCII y caracteres de control. Agregue una pestaña después de ^
si puede haber pestañas en el archivo. Agregue un retorno de carro si puede haber finales de línea de Windows que no desea que coincidan. En bash o zsh, puedes usar $'…'
comillas y \t
para una tabulación, \r
para un retorno de carro.
LC_ALL=C grep $'[^\t\r -~]' file.xml
Con otros shells que no son compatibles $'…'
, de forma interactiva, puede insertar caracteres de control literalmente con, por ejemplo , . En un script, es posible que prefiera no incluir el carácter de control literalmente en el script y, en su lugar, generarlo en tiempo de ejecución.Ctrl+V Ctrl+M
control_characters=$(printf '\t\r')
LC_ALL=C grep "[^${control_characters} -~]" file.xml
Para evitar que coincida con cualquier carácter de control, utilice el rango de caracteres ASCII (excluyendo nulo que no se puede especificar en la línea de comando). Con GNU grep, los caracteres de control normalmente dan como resultado el mensaje "coincidencias de archivos binarios" en lugar de imprimir coincidencias; pase la --text
opción para mostrar caracteres de control en la salida.
LC_ALL=C grep --text $'[^\001-~]' file.xml
La configuración LC_COLLATE=C
evita sorpresas desagradables sobre el significado de los rangos de caracteres en muchos lugares. La configuración LC_CTYPE=C
es necesaria para que coincida con caracteres de un solo byte; de lo contrario, el comando omitiría secuencias de bytes no válidas en la codificación actual. La configuración LC_ALL=C
evita por completo los efectos dependientes de la ubicación.
Lo siguiente me funciona:
grep -P "[\x80-\xFF]" file.xml
Los caracteres que no son ASCII comienzan en 0x80 y llegan a 0xFF cuando se miran bytes. Grep (y su familia) no realizan 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 my grep permite el uso de \xdd
escapes en clases de personajes para lograr lo que deseas.