Recabamos en todo el mundo on line para así tener para ti la solución a tu duda, si continúas con alguna inquietud puedes dejarnos tu duda y responderemos sin falta.
Solución:
Si quieres usar grep
, tu puedes hacer:
grep -axv '.*' file
en configuraciones regionales UTF-8 para obtener las líneas que tienen al menos una secuencia UTF-8 no válida (esto funciona con GNU Grep al menos).
Creo que probablemente quieras iconv. Es para convertir entre conjuntos de códigos y admite una cantidad absurda de formatos. Por ejemplo, para eliminar cualquier cosa que no sea válida en UTF-8, puede usar:
iconv -c -t UTF-8 < input.txt > output.txt
Sin la opción -c, informará problemas al convertir a stderr, por lo que con la dirección del proceso podría guardar una lista de estos. Otra forma sería quitar las cosas que no son UTF8 y luego
diff input.txt output.txt
para obtener una lista de dónde se realizaron los cambios.
Editar: He corregido un error tipográfico en la expresión regular. Necesitaba un ‘ x80` no 80.
La expresión regular para filtrar formularios UTF-8 no válidos, por estricto la adherencia a UTF-8, es la siguiente
perl -l -ne '/
^( ([x00-x7F]) # 1-byte pattern
|([xC2-xDF][x80-xBF]) # 2-byte pattern
|((([xE0][xA0-xBF])|([xED][x80-x9F])|([xE1-xECxEE-xEF][x80-xBF]))([x80-xBF])) # 3-byte pattern
|((([xF0][x90-xBF])|([xF1-xF3][x80-xBF])|([xF4][x80-x8F]))([x80-xBF]2)) # 4-byte pattern
)*$ /x or print'
Salida (de líneas clave. De Prueba 1):
Codepoint
=========
00001000 Test=1 mode=strict valid,invalid,fail=(1000,0,0)
0000E000 Test=1 mode=strict valid,invalid,fail=(D800,800,0)
0010FFFF mode=strict test-return=(0,0) valid,invalid,fail=(10F800,800,0)
P. ¿Cómo se crean datos de prueba para probar una expresión regular que filtra Unicode no válido?
A. Cree su propio algoritmo de prueba UTF-8 y rompa sus reglas …
22 capturas.. Pero entonces, ¿cómo prueba su algoritmo de prueba?
La expresión regular, arriba, ha sido probada (usando iconv
como referencia) para cada valor entero de 0x00000
para 0x10FFFF
.. Este valor superior es el valor entero máximo de un punto de código Unicode
- En noviembre de 2003, RFC 3629 restringió UTF-8 a cuatro bytes que cubren solo el rango U + 0000 a U + 10FFFF, para que coincida con las restricciones de la codificación de caracteres UTF-16.
Según esta página de wikipedia UTF-8,.
- UTF-8 codifica cada uno de los 1,112,064 puntos de código en el juego de caracteres Unicode, usando de uno a cuatro bytes de 8 bits
Este numeber (1,112,064) equivale a un rango 0x000000
para 0x10F7FF
, que es 0x0800 por debajo del valor entero máximo real para el punto de código Unicode más alto: 0x10FFFF
Esta bloque de enteros falta en el espectro de puntos de código Unicode, debido a la necesidad de codificación UTF-16 para dar un paso más allá de su intención de diseño original a través de un sistema llamado pares sustitutos. Un bloque de 0x0800
enteros se ha reservado para ser utilizado por UTF-16 .. Este bloque abarca el rango0x00D800
para 0x00DFFF
. Ninguno de estos números enteros son valores Unicode legales y, por lo tanto, son valores UTF-8 no válidos.
En Prueba 1, los regex
ha sido probado contra todos los números en el rango de puntos de código Unicode, y coincide exactamente con los resultados de iconv
.. es decir. 0x010F7FF valores válidos, y 0x000800 valores inválidos.
Sin embargo, ahora surge el problema de: * ¿Cómo maneja la expresión regular el valor UTF-8 fuera de rango? encima 0x010FFFF
(UTF-8 puede extenderse a 6 bytes, con un valor entero máximo de 0x7FFFFFFF?
Para generar los necesarios *valores de bytes UTF-8 no Unicode, He usado el siguiente comando:
perl -C -e 'print chr 0x'$hexUTF32BE
Para probar su validez (de alguna manera), he usado Gilles'
UTF-8 regex …
perl -l -ne '/
^( [ 00-177] # 1-byte pattern
|[300-337][200-277] # 2-byte pattern
|[340-357][200-277]2 # 3-byte pattern
|[360-367][200-277]3 # 4-byte pattern
|[370-373][200-277]4 # 5-byte pattern
|[374-375][200-277]5 # 6-byte pattern
)*$ /x or print'
La salida de ‘perl’s print chr’ coincide con el filtrado de la expresión regular de Gilles. Una refuerza la validez de la otra. No puedo usar iconv
porque solo maneja el subconjunto del estándar Unicode válido del estándar UTF-8 más amplio (original) …
Los nunbers involucrados son bastante grandes, por lo que he probado el tope de rango, el fondo de rango y varios escaneos escalonados en incrementos como, 11111, 13579, 33333, 53441 … Todos los resultados coinciden, así que ahora todo lo que queda es probar la expresión regular contra estos valores de estilo UTF-8 fuera de rango (no válidos para Unicode y, por lo tanto, también no son válidos para el propio UTF-8 estricto).
Aquí están los módulos de prueba:
[[ "$(locale charmap)" != "UTF-8" ]] && echo "ERROR: locale must be UTF-8, but it is $(locale charmap)"; exit 1;
# Testing the UTF-8 regex
#
# Tests to check that the observed byte-ranges (above) have
# been accurately observed and included in the test code and final regex.
# =========================================================================
: 2 bytes; B2=0 # run-test=1 do-not-test=0
: 3 bytes; B3=0 # run-test=1 do-not-test=0
: 4 bytes; B4=0 # run-test=1 do-not-test=0
: regex; Rx=1 # run-test=1 do-not-test=0
((strict=16)); mode[$strict]=strict # iconv -f UTF-16BE then iconv -f UTF-32BE beyond 0xFFFF)
(( lax=32)); mode[$lax]=lax # iconv -f UTF-32BE only)
# modebits=$strict
# UTF-8, in relation to UTF-16 has invalid values
# modebits=$strict automatically shifts to modebits=$lax
# when the tested integer exceeds 0xFFFF
# modebits=$lax
# UTF-8, in relation to UTF-32, has no restrictione
# Test 1 Sequentially tests a range of Big-Endian integers
# * Unicode Codepoints are a subset ofBig-Endian integers
# ( based on 'iconv' -f UTF-32BE -f UTF-8 )
# Note: strict UTF-8 has a few quirks because of UTF-16
# Set modebits=16 to "strictly" test the low range
Test=1; modebits=$strict
# Test=2; modebits=$lax
# Test=3
mode3wlo=$(( 1*4)) # minimum chars * 4 ( '4' is for UTF-32BE )
mode3whi=$((10*4)) # minimum chars * 4 ( '4' is for UTF-32BE )
#########################################################################
# 1 byte UTF-8 values: Nothing to do; no complexities.
#########################################################################
# 2 Byte UTF-8 values: Verifying that I've got the right range values.
if ((B2==1)) ; then
echo "# Test 2 bytes for Valid UTF-8 values: ie. values which are in range"
# =========================================================================
time
for d1 in 194..223 ;do
# bin oct hex dec
# lo 11000010 302 C2 194
# hi 11011111 337 DF 223
B2b1=$(printf "%0.2X" $d1)
#
for d2 in 128..191 ;do
# bin oct hex dec
# lo 10000000 200 80 128
# hi 10111111 277 BF 191
B2b2=$(printf "%0.2X" $d2)
#
echo -n "$B2b1$B2b2" |
xxd -p -u -r |
iconv -f UTF-8 >/dev/null ||
echo "ERROR: Invalid UTF-8 found: $B2b1$B2b2"; exit 20;
#
done
done
echo
# Now do a negated test.. This takes longer, because there are more values.
echo "# Test 2 bytes for Invalid values: ie. values which are out of range"
# =========================================================================
# Note: 'iconv' will treat a leading x00-x7F as a valid leading single,
# so this negated test primes the first UTF-8 byte with values starting at x80
time
for d1 in 128..193 224..255 ;do
#for d1 in 128..194 224..255 ;do # force a valid UTF-8 (needs $B2b2)
B2b1=$(printf "%0.2X" $d1)
#
for d2 in 0..127 192..255 ;do
#for d2 in 0..128 192..255 ;do # force a valid UTF-8 (needs $B2b1)
B2b2=$(printf "%0.2X" $d2)
#
echo -n "$B2b1$B2b2" |
xxd -p -u -r |
iconv -f UTF-8 2>/dev/null &&
echo "ERROR: VALID UTF-8 found: $B2b1$B2b2"; exit 21;
#
done
done
echo
fi
#########################################################################
# 3 Byte UTF-8 values: Verifying that I've got the right range values.
if ((B3==1)) ; then
echo "# Test 3 bytes for Valid UTF-8 values: ie. values which are in range"
# ========================================================================
time
for d1 in 224..239 ;do
# bin oct hex dec
# lo 11100000 340 E0 224
# hi 11101111 357 EF 239
B3b1=$(printf "%0.2X" $d1)
#
if [[ $B3b1 == "E0" ]] ; then
B3b2range="$(echo 160..191)"
# bin oct hex dec
# lo 10100000 240 A0 160
# hi 10111111 277 BF 191
elif [[ $B3b1 == "ED" ]] ; then
B3b2range="$(echo 128..159)"
# bin oct hex dec
# lo 10000000 200 80 128
# hi 10011111 237 9F 159
else
B3b2range="$(echo 128..191)"
# bin oct hex dec
# lo 10000000 200 80 128
# hi 10111111 277 BF 191
fi
#
for d2 in $B3b2range ;do
B3b2=$(printf "%0.2X" $d2)
echo "$B3b1 $B3b2 xx"
#
for d3 in 128..191 ;do
# bin oct hex dec
# lo 10000000 200 80 128
# hi 10111111 277 BF 191
B3b3=$(printf "%0.2X" $d3)
#
echo -n "$B3b1$B3b2$B3b3" |
xxd -p -u -r |
iconv -f UTF-8 >/dev/null ||
echo "ERROR: Invalid UTF-8 found: $B3b1$B3b2$B3b3"; exit 30;
#
done
done
done
echo
# Now do a negated test.. This takes longer, because there are more values.
echo "# Test 3 bytes for Invalid values: ie. values which are out of range"
# =========================================================================
# Note: 'iconv' will treat a leading x00-x7F as a valid leading single,
# so this negated test primes the first UTF-8 byte with values starting at x80
#
# real 26m28.462s
# user 27m12.526s | stepping by 2
# sys 13m11.193s /
#
# real 239m00.836s
# user 225m11.108s | stepping by 1
# sys 120m00.538s /
#
time
for d1 in 128..223..1 240..255..1 ;do
#for d1 in 128..224..1 239..255..1 ;do # force a valid UTF-8 (needs $B2b2,$B3b3)
B3b1=$(printf "%0.2X" $d1)
#
if [[ $B3b1 == "E0" ]] ; then
B3b2range="$(echo 0..159..1 192..255..1)"
#B3b2range="$(> 192..255..1)" # force a valid UTF-8 (needs $B3b1,$B3b3)
elif [[ $B3b1 == "ED" ]] ; then
B3b2range="$(echo 0..127..1 160..255..1)"
#B3b2range="$(echo 0..128..1 160..255..1)" # force a valid UTF-8 (needs $B3b1,$B3b3)
else
B3b2range="$(echo 0..127..1 192..255..1)"
#B3b2range="$(echo 0..128..1 192..255..1)" # force a valid UTF-8 (needs $B3b1,$B3b3)
fi
for d2 in $B3b2range ;do
B3b2=$(printf "%0.2X" $d2)
echo "$B3b1 $B3b2 xx"
#
for d3 in 0..127..1 192..255..1 ;do
#for d3 in 0..128..1 192..255..1 ;do # force a valid UTF-8 (needs $B2b1)
B3b3=$(printf "%0.2X" $d3)
#
echo -n "$B3b1$B3b2$B3b3" |
xxd -p -u -r |
iconv -f UTF-8 2>/dev/null &&
echo "ERROR: VALID UTF-8 found: $B3b1$B3b2$B3b3"; exit 31;
#
done
done
done
echo
fi
#########################################################################
# Brute force testing in the Astral Plane will take a VERY LONG time..
# Perhaps selective testing is more appropriate, now that the previous tests
# have panned out okay...
#
# 4 Byte UTF-8 values:
if ((B4==1)) ; then
echo "# Test 4 bytes for Valid UTF-8 values: ie. values which are in range"
# ==================================================================
# real 58m18.531s
# user 56m44.317s |
# sys 27m29.867s /
time
for d1 in 240..244 ;do
# bin oct hex dec
# lo 11110000 360 F0 240
# hi 11110100 364 F4 244 -- F4 encodes some values greater than 0x10FFFF;
# such a sequence is invalid.
B4b1=$(printf "%0.2X" $d1)
#
if [[ $B4b1 == "F0" ]] ; then
B4b2range="$(echo 144..191)" ## f0 90 80 80 to f0 bf bf bf
# bin oct hex dec 010000 -- 03FFFF
# lo 10010000 220 90 144
# hi 10111111 277 BF 191
#
elif [[ $B4b1 == "F4" ]] ; then
B4b2range="$(echo 128..143)" ## f4 80 80 80 to f4 8f bf bf
# bin oct hex dec 100000 -- 10FFFF
# lo 10000000 200 80 128
# hi 10001111 217 8F 143 -- F4 encodes some values greater than 0x10FFFF;
# such a sequence is invalid.
else
B4b2range="$(echo 128..191)" ## fx 80 80 80 to f3 bf bf bf
# bin oct hex dec 0C0000 -- 0FFFFF
# lo 10000000 200 80 128 0A0000
# hi 10111111 277 BF 191
fi
#
for d2 in $B4b2range ;do
B4b2=$(printf "%0.2X" $d2)
#
for d3 in 128..191 ;do
# bin oct hex dec
# lo 10000000 200 80 128
# hi 10111111 277 BF 191
B4b3=$(printf "%0.2X" $d3)
echo "$B4b1 $B4b2 $B4b3 xx"
#
for d4 in 128..191 ;do
# bin oct hex dec
# lo 10000000 200 80 128
# hi 10111111 277 BF 191
B4b4=$(printf "%0.2X" $d4)
#
echo -n "$B4b1$B4b2$B4b3$B4b4" |
xxd -p -u -r |
iconv -f UTF-8 >/dev/null ||
echo "ERROR: Invalid UTF-8 found: $B4b1$B4b2$B4b3$B4b4"; exit 40;
#
done
done
done
done
echo "# Test 4 bytes for Valid UTF-8 values: END"
echo
fi
########################################################################
# There is no test (yet) for negated range values in the astral plane. #
# (all negated range values must be invalid) #
# I won't bother; This was mainly for me to ge the general feel of #
# the tests, and the final test below should flush anything out.. #
# Traversing the intire UTF-8 range takes quite a while... #
# so no need to do it twice (albeit in a slightly different manner) #
########################################################################
################################
### The construction of: ####
### The Regular Expression ####
### (de-construction?) ####
################################
# BYTE 1 BYTE 2 BYTE 3 BYTE 4
# 1: [x00-x7F]
# ===========
# ([x00-x7F])
#
# 2: [xC2-xDF] [x80-xBF]
# =================================
# ([xC2-xDF][x80-xBF])
#
# 3: [xE0] [xA0-xBF] [x80-xBF]
# [xED] [x80-x9F] [x80-xBF]
# [xE1-xECxEE-xEF] [x80-xBF] [x80-xBF]
# ==============================================
# ((([xE0][xA0-xBF])|([xED][x80-x9F])|([xE1-xECxEE-xEF][x80-xBF]))([x80-xBF]))
#
# 4 [xF0] [x90-xBF] [x80-xBF] [x80-xBF]
# [xF1-xF3] [x80-xBF] [x80-xBF] [x80-xBF]
# [xF4] [x80-x8F] [x80-xBF] [x80-xBF]
# ===========================================================
# ((([xF0][x90-xBF])|([xF1-xF3][x80-xBF])|([xF4][x80-x8F]))([x80-xBF]2))
#
# The final regex
# ===============
# 1-4: (([x00-x7F])|([xC2-xDF][x80-xBF])|((([xE0][xA0-xBF])|([xED][x80-x9F])|([xE1-xECxEE-xEF][x80-xBF]))([x80-xBF]))|((([xF0][x90-xBF])|([xF1-xF3][x80-xBF])|([xF4][x80-x8F]))([x80-xBF]2)))
# 4-1: (((([xF0][x90-xBF])|([xF1-xF3][x80-xBF])|([xF4][x80-x8F]))([x80-xBF]2))|((([xE0][xA0-xBF])|([xED][x80-x9F])|([xE1-xECxEE-xEF][x80-xBF]))([x80-xBF]))|([xC2-xDF][x80-xBF])|([x00-x7F]))
#######################################################################
# The final Test; for a single character (multi chars to follow) #
# Compare the return code of 'iconv' against the 'regex' #
# for the full range of 0x000000 to 0x10FFFF #
# #
# Note; this script has 3 modes: #
# Run this test TWICE, set each mode Manually! #
# #
# 1. Sequentially test every value from 0x000000 to 0x10FFFF #
# 2. Throw a spanner into the works! Force random byte patterns #
# 2. Throw a spanner into the works! Force random longer strings #
# ============================== #
# #
# Note: The purpose of this routine is to determine if there is any #
# difference how 'iconv' and 'regex' handle the same data #
# #
#######################################################################
if ((Rx==1)) ; then
# real 191m34.826s
# user 158m24.114s
# sys 83m10.676s
time ((([xE0][xA0-xBF]) # End time
fi
exit
Te mostramos reseñas y calificaciones
Nos puedes auxiliar nuestro estudio ejecutando un comentario o dejando una valoración te damos las gracias.