Substitui toda a ocorrência de caractere, exceto a primeira [duplicata]

8

Eu tenho um arquivo de texto da seguinte forma:

test1,test2,test3
test4,test5
test6,test7,test8,test9,test10
test11,test12,test13,test14

Como posso substituir vírgulas por ponto e vírgula, começando com o segundo (e continuando até o último)?

Eu quero obter a saída da seguinte forma:

test1,test2;test3
test4,test5
test6,test7;test8;test9;test10
test11,test12;test13;test14
    
por alrz 06.09.2016 / 07:52

5 respostas

7

Se a entrada já tiver pontos e vírgulas, precisamos ter cuidado:

$ sed 's/,/\n/g; s/\n/,/; s/\n/;/g' input
test1,test2;test3
test4,test5
test6,test7;test8;test9;test10
test11,test12;test13;test14

Como o sed lê a entrada linha por linha, não haverá caracteres de nova linha na entrada normal. Assim, podemos substituir todas as vírgulas por novas linhas e sabemos que não haverá confusão. Em seguida, restauramos a primeira nova linha de volta a uma vírgula. Por fim, substituímos todas as novas linhas restantes por um ponto e vírgula.

Mais detalhadamente:

  • s/,/\n/g substitui todas as vírgulas por novas linhas.

  • s/\n/,/ substitui a primeira nova linha por uma vírgula.

  • s/\n/;/g substitui todas as novas linhas restantes por ponto e vírgula.

por 06.09.2016 / 08:08
13

Isso pode ser feito com isso,

$ sed -e 's/,/;/g' -e 's/;/,/1' infile
test1,test2;test3
test4,test5
test6,test7;test8;test9;test10
test11,test12;test13;test14

Explicação

  • s/,/;/g substitui toda a ocorrência de , por ;

  • s/;/,/1 substitui a primeira ocorrência de ; por ,

Se você tem o GNU sed , você também pode tentar isso simples e útil,

sed 's/,/;/2g' infile
    
por 06.09.2016 / 08:08
2

Usando awk :

awk '{gsub(",", ";"); sub(";", ","); print}' file.txt
  • gsub(",", ";") substitui todos os , por ;

  • sub(";", ",") substitui o primeiro ; por ,

Exemplo:

% cat file.txt
test1,test2,test3
test4,test5
test6,test7,test8,test9,test10
test11,test12,test13,test14

% awk '{gsub(",", ";"); sub(";", ","); print}' file.txt
test1,test2;test3
test4,test5
test6,test7;test8;test9;test10
test11,test12;test13;test14
    
por 06.09.2016 / 08:55
2
$ cat ip.txt 
test1,test2,test3
test4,test5
test6,test7,test8,test9,test10
test11,test12,test13,test14
test15

$ perl -F, -ane 'print "$F[0]"; print ",".join(";",@F[1..$#F]) if($#F > 0)' ip.txt 
test1,test2;test3
test4,test5
test6,test7;test8;test9;test10
test11,test12;test13;test14
test15


Outra maneira:

perl -F'/(,)/,$_,2' -ane '$F[2] =~ s/,/;/g; print @F'
  • /(,)/,$_,2 split $_ (a linha de entrada) em dois baseado em , Como (,) é usado, ele captura o separador, resultando em três elementos, conforme explicado abaixo
  • $F[0] obtém o primeiro campo, $F[1] receberá , se presente
  • $F[2] obtém campos restantes se presente


Ainda outra maneira, emulando sed 's/,/;/2g'

perl -pe '$c=0; s/,/++$c<2 ? $& : ";"/ge' ip.txt
  • inicializa o contador para cada linha
  • ao substituir, verifique o valor do contador conforme necessário
  • o modificador e permite o código Perl na seção de substituição
por 06.09.2016 / 09:26
1

Solução em TXR Lisp:

txr -e  '(each ((line (get-lines)))
           (set [line (rest (where (op eql #\,) line))]
                (repeat ";"))
           (put-line line))' < input

"Para cada linha, defina o resto dos lugares (ou seja, todos, mas o primeiro lugar), onde essa linha é igual a vírgula, a um ponto-e-vírgula. Saída da linha."

Transcrição anotada da sessão de ouvinte interativo de fundo:

$ txr
This is the TXR Lisp interactive listener of TXR 148.
Use the :quit command or type Ctrl-D on empty line to exit.

Lista de infinitas lazy de ponto e vírgula:

1> (take 3 (repeat ";"))
(#\; #\; #\;)

Ligação variável:

2> (let ((a "a,b,c"))
     a)
"a,b,c"

A notação de suporte extrai índices:

3> (let ((a "a,b,c"))
     [a '(1 3)])
",,"
A função

where extrai posições em que o predicado é verdadeiro:

4> (let ((a "a,b,c"))
     (where (op eql #\,) a))
(1 3)

Atribuir uma sequência a um lugar denotado por notação quadrada com a lista de índices faz com que esses índices sejam substituídos por elementos da sequência, não levando mais do que elementos suficientes para satisfazer os índices:

5> (let ((a "a,b,c"))
     (set [a '(1 3)] (repeat ";"))
     a)
"a;b;c"

Calcule dinamicamente os índices com where :

6> (let ((a "a,b,c"))
     (set [a (where (op eql #\,) a)] (repeat ";"))
     a)
"a;b;c"

Cortar o primeiro índice com rest , para evitar a primeira vírgula com ponto-e-vírgula:

7> (let ((a "a,b,c"))
     (set [a (rest (where (op eql #\,) a))] (repeat ";"))
     a)
"a,b;c"

Teste com outras strings. Ops, "" não é modificável:

8> (let ((a ""))
     (set [a (rest (where (op eql #\,) a))] (repeat ";"))
     a)
** replace-str: "" of type lit is not a modifiable string
** during evaluation of form (sys:dwim-set a #:g0145 #:g0144)
** ... an expansion at expr-8:2 of (sys:dwim-set (#:g0146) #:g0145
                                                 #:g0144)
** which is located at expr-8:2

Tente novamente:

9> (let ((a (copy "")))
     (set [a (rest (where (op eql #\,) a))] (repeat ";"))
     a)
""

String sem vírgulas:

10> (let ((a "a"))
     (set [a (rest (where (op eql #\,) a))] (repeat ";"))
     a)
"a"

String com apenas uma vírgula: nenhuma substituição ocorre.

11> (let ((a "a,b"))
     (set [a (rest (where (op eql #\,) a))] (repeat ";"))
     a)
"a,b"
    
por 06.09.2016 / 23:31