Eu tenho um arquivo csv enorme com 10 campos separados por vírgulas. Infelizmente, algumas linhas estão malformadas e não contêm exatamente 10 vírgulas (o que causa alguns problemas quando desejo ler o arquivo no R). Como filtrar apenas as linhas que contêm exatamente 10 vírgulas?
9
sed
é o caso aqui) apenas na medida em que mais uma correspondência do que a esperada, embora essa pergunta exija. Você não deveria ter fechado isso.grep
resposta não é uma resposta aceitável para uma dessas perguntas ...Respostas:
Outro POSIX:
Se a linha tiver 10 vírgulas, haverá 11 campos nessa linha. Então, simplesmente fazemos
awk
uso,
como delimitador de campo. Se o número de campos for 11, a condiçãoNF == 11
é verdadeira e, emawk
seguida , executa a ação padrãoprint $0
.fonte
-F
define o separador de campos eNF
refere-se ao número de campos em uma determinada linha. Como nenhum bloco de código{statement}
é anexado à condiçãoNF == 11
, a ação padrão é imprimir a linha. (@cuonglm, sinta-se livre para incorporar esta explicação, se quiser.)awk -F , 'NF != 11' <file
-
ou o nome dele-
.Usando
egrep
(ougrep -E
no POSIX):Isso filtra qualquer coisa que não contenha 10 vírgulas: corresponde a linhas completas (
^
no início e$
no final), contendo exatamente dez repetições ({10}
) da sequência "qualquer número de caracteres, exceto ',', seguido por um único ','" (([^,]*,)
), seguido novamente por qualquer número de caracteres, exceto ',' ([^,]*
).Você também pode usar o
-x
parâmetro para soltar as âncoras:Isso é menos eficiente que a solução da cuonglm
awk
; o último é normalmente seis vezes mais rápido no meu sistema para linhas com cerca de 10 vírgulas. Linhas mais longas causarão grandes desacelerações.fonte
O
grep
código mais simples que funcionará:Explicação:
-x
garante que o padrão deve corresponder à linha inteira , em vez de apenas parte dela. Isso é importante para que você não combine as linhas com mais de 10 vírgulas.-E
significa "regex estendido", o que reduz o escape da barra invertida no seu regex.Os parênteses são usados para agrupar e,
{10}
posteriormente, significa que deve haver exatamente dez correspondências em uma linha do padrão entre parênteses.[^,]
é uma classe de caracteres - por exemplo,[c-f]
corresponderia a qualquer caractere único ac
, ad
, ane
ou anf
e[^A-Z]
corresponderia a qualquer caractere único que NÃO seja uma letra maiúscula. Portanto,[^,]
corresponde a qualquer caractere, exceto uma vírgula.A
*
classe após o caractere significa "zero ou mais destes".Portanto, a parte regex
([^,]*,)
significa "Qualquer caractere, exceto uma vírgula, qualquer número de vezes (incluindo zero vezes), seguido por uma vírgula" e{10}
especifica 10 deles. Em seguida,[^,]*
para corresponder o restante dos caracteres que não são vírgulas até o final da linha.fonte
Isso primeiro ramifica qualquer linha com 11 ou mais vírgulas e depois imprime o que resta apenas aqueles que correspondem a 10 vírgulas.
Aparentemente, eu já respondi isso antes ... Aqui está um plágio de uma pergunta que procura exatamente 4 ocorrências de algum padrão:
fonte
s/hello/world/2
pors//world/2
, o GNU sed funcione bem. Com doissed
da herança,/usr/5bin/posix/sed
levante segfault,/usr/5bin/sed
entra em loop infinitivo.sed
eawk
(nos comentários) - eu gosto desta resposta e a votei positivamente, mas observe que a tradução daawk
resposta aceita é: "Imprima linhas com 11 campos" e a tradução destased
resposta é: " Tente remover a 11ª vírgula; pule para a próxima linha se você falhar. Tente substituir a 10ª vírgula por si mesma; imprima a linha se tiver êxito. " Aawk
resposta fornece as instruções para o computador da maneira que você as expressaria em inglês. (awk
é bom para dados baseados em campo).Jogando um pouco curto
python
:Isso lerá cada linha e verificará se o número de vírgulas na linha é igual a 10
line.count(',') == 10
; caso contrário, imprima a linha.fonte
E aqui está uma maneira Perl:
As
-n
causasperl
para ler seu arquivo de entrada linha por linha e executar o script fornecido-e
em cada linha. As-a
curvas na divisão automática: cada linha de entrada será dividida no valor dado por-F
(aqui, uma vírgula) e guardado como a matriz@F
.O
$#F
(ou, de maneira mais geral$#array
), é o índice mais alto da matriz@F
. Como as matrizes começam em0
, uma linha com 11 campos terá um@F
de10
. O script, portanto, imprime a linha se tiver exatamente 11 campos.fonte
print if @F==11
como uma matriz em um contexto escalar retorna o número de elementos.Se os campos puderem conter vírgulas ou novas linhas, seu código precisará entender csv. Exemplo (com três colunas):
Suponho que a maioria das soluções até agora descartaria a segunda e a quarta linha.
fonte