Tengo un gran archivo csv con 10 campos separados por comas. Desafortunadamente, algunas líneas están mal formadas y no contienen exactamente 10 comas (lo que causa algunos problemas cuando quiero leer el archivo en R). ¿Cómo puedo filtrar solo las líneas que contienen exactamente 10 comas?
9
sed
hace aquí) solo hasta una coincidencia más de la que se busca, aunque esta pregunta sí. No deberías haber cerrado esto.grep
respuesta no es una respuesta aceptable para ninguna de las preguntas ...Respuestas:
Otro POSIX:
Si la línea tiene 10 comas, habrá 11 campos en esta línea. Así que simplemente hacemos
awk
uso,
como delimitador de campo. Si el número de campos es 11, la condiciónNF == 11
es verdadera,awk
luego realiza la acción predeterminadaprint $0
.fuente
-F
establece el separador de campo y seNF
refiere al número de campos en una línea dada. Como no{statement}
se agrega ningún bloque de código a la condiciónNF == 11
, la acción predeterminada es imprimir la línea. (@cuonglm, siéntase libre de incorporar esta explicación si lo desea.)awk -F , 'NF != 11' <file
-
o con nombre-
.Usando
egrep
(ogrep -E
en POSIX):Esto filtra cualquier cosa que no contenga 10 comas: coincide con líneas completas (
^
al principio y$
al final), que contiene exactamente diez repeticiones ({10}
) de la secuencia "cualquier número de caracteres excepto ',', seguido de un solo ','" (([^,]*,)
), seguido de nuevo por cualquier número de caracteres excepto ',' ([^,]*
).También puede usar el
-x
parámetro para soltar los anclajes:Esto es menos eficiente que cuonglm 's
awk
solución sin embargo; este último es típicamente seis veces más rápido en mi sistema para líneas con alrededor de 10 comas. Las líneas más largas causarán grandes ralentizaciones.fuente
El
grep
código más simple que funcionará:Explicación:
-x
asegura que el patrón debe coincidir con la línea completa , en lugar de solo una parte de ella. Esto es importante para que no coincidan las líneas con más de 10 comas.-E
significa "expresión regular extendida", lo que hace que se reduzca la barra invertida en su expresión regular.Los paréntesis se usan para agrupar, y
{10}
luego significa que debe haber exactamente diez coincidencias en una fila del patrón dentro de las paréntesis.[^,]
es una clase de caracteres; por ejemplo,[c-f]
coincidiría con cualquier carácter único que sea ac
, ad
, ane
o anf
, y[^A-Z]
coincidiría con cualquier carácter único que NO sea una letra mayúscula. Por lo tanto,[^,]
coincide con cualquier carácter, excepto una coma.El
*
después de que los medios de clase de caracteres "cero o más de estos."Entonces, la parte regex
([^,]*,)
significa "Cualquier carácter excepto una coma cualquier número de veces (incluyendo cero veces), seguido de una coma" y{10}
especifica 10 de estos. Luego,[^,]*
para que coincida con el resto de los caracteres que no son comas al final de la línea.fuente
Eso primero ramifica cualquier línea con 11 o más comas, y luego imprime lo que queda solo aquellas que coinciden con 10 comas.
Aparentemente respondí esto antes ... Aquí hay un plagio de mí de una pregunta que busca exactamente 4 ocurrencias de algún patrón:
fuente
s/hello/world/2
cons//world/2
, GNU funciona bien. Con dossed
de reliquia,/usr/5bin/posix/sed
eleva segfault,/usr/5bin/sed
entra en bucle infinitivo.sed
yawk
(en comentarios): me gusta esta respuesta y la voté, pero observe que la traducción de laawk
respuesta aceptada es: "Imprimir líneas con 11 campos" y la traducción de estased
respuesta es: " Intenta eliminar la undécima coma; salta a la siguiente línea si fallas. Intenta reemplazar la décima coma por sí misma; imprime la línea si tienes éxito ". Laawk
respuesta da las instrucciones a la computadora tal como las expresarías en inglés. (awk
es bueno para datos basados en campo).Lanzando algo corto
python
:Esto leerá cada línea y verificará si el número de comas en la línea es igual a 10
line.count(',') == 10
, si es así, imprima la línea.fuente
Y aquí hay una manera de Perl:
Las
-n
causasperl
para leer su archivo de entrada línea por línea y ejecutar el script dado por-e
en cada línea. Se-a
activa la división automática: cada línea de entrada se dividirá en el valor dado por-F
(aquí, una coma) y se guardará como la matriz@F
.El
$#F
(o, más generalmente$#array
), es el índice más alto de la matriz@F
. Como las matrices comienzan en0
, una línea con 11 campos tendrá un@F
de10
. El script, por lo tanto, imprime la línea si tiene exactamente 11 campos.fuente
print if @F==11
que una matriz en un contexto escalar devuelva el número de elementos.Si los campos pueden contener comas o líneas nuevas, su código debe comprender csv. Ejemplo (con tres columnas):
Supongo que la mayoría de las soluciones hasta ahora descartarían la segunda y cuarta fila.
fuente