Você provavelmente quer :%s/\v(([^,]*,){3})([0-9]+),([0-9])//
.
Seu objetivo é remover uma vírgula do quarto campo, se presente, sem remover vírgulas em outro lugar e sem remover nenhum outro texto. O fator complicador é que as vírgulas também são usadas como separadores de campo. Para resolver o problema, você deve considerar o que sabe sobre as condições sob as quais as vírgulas podem aparecer dentro de um campo. Afinal, sem mais restrições, seus registros são ambíguos.
É tentador considerar qualquer vírgula abrangendo dois dígitos como assunto para remoção, mas isso não funcionará. Sua amostra de entrada mostra que você pode ter um final de campo com um dígito e o próximo campo começa com um ( col2,35,000
).
Se você sabe que os três primeiros campos não contêm vírgulas, o problema se torna muito mais fácil, porque as três primeiras sequências de zero ou mais não-vírgulas seguidas por vírgulas podem ser ignoradas antes da remoção de vírgulas. Então a questão é como descobrir quando o quarto campo terminou. Você deve se perguntar se deseja remover vírgulas múltiplas do quarto campo, ou se é sempre sem vírgulas ou uma vírgula.
Eu assumirei, para o bem desta resposta, que o quarto campo contém no máximo uma vírgula que deve ser removida. Além disso, assumirei que a vírgula aparece após um ou mais dígitos e antes de pelo menos um dígito. Então você pode usar isso no Vim:
:%s/\v(([^,]*,){3})([0-9]+),([0-9])//
Ou, se você preferir usar Sed:
sed -r 's/(([^,]*,){3})([0-9]+),([0-9])//' filename.csv
Como funciona
A expressão regular (([^,]*,){3})
corresponde aos três primeiros campos e aos separadores de campos que os seguem, os quais você desejará manter sempre. [^,]
corresponde a qualquer caractere único, mas ,
. O *
depois faz com que zero ou mais deles sejam correspondidos em vez de exatamente um. O ,
depois disso corresponde à vírgula real que segue este campo de não-vírgulas. Isso tudo é agrupado com (
)
e o {3}
aplicado a ele faz com que seja correspondido três vezes em vez de uma vez. Então essa coisa toda é agrupada para que possa ser acessada com . (O grupo interno também captura e poderia ser acessado como
.)
Em seguida, ([0-9]+)
corresponde a um ou mais dígitos ( +
) ( [0-9]
) e captura a correspondência ( (
)
) para que possa ser acessada como . O caractere
,
corresponde a uma vírgula literal; essa é a parte que não iremos manter. Então, ([0-9])
captura um único dígito para que possa ser acessado como .
Você pode tornar a expressão regular um pouco mais simples usando um único grupo para e
, ou seja,
(([^,]*,){3}[0-9]+)
. Evitei isso porque sinto que isso esconde a estrutura dos seus registros - que eles são compostos de campos separados por vírgulas - mas não há nada de errado em fazer dessa maneira. Se você fez isso, se tornaria
, então no padrão de substituição você usaria
em vez de
.
Por fim, o \v
no início do Vim regex e o -r
passado para o sed
serve para permitir que você use a sintaxe de expressão regular estendida. É por isso que consegui escrever (
e )
em vez de \(
e \)
e +
em vez de \+
.