Acrescentar um caractere na enésima posição de uma string correspondente

1

Eu preciso encontrar um comando sed / awk que irá inserir um caractere na n-ésima posição de uma string correspondente. COMPRIMENTO DE COMPRIMENTO 10. Por exemplo, eu preciso procurar a string começando com o padrão 541 e tendo comprimento 10, em seguida, insira 9 na quinta posição dessa sequência sem substituição, resultando em uma sequência de 11 caracteres.

As cadeias são palavras separadas por espaços em branco. Além disso, o padrão sempre estará no início da palavra, mas pode haver várias correspondências por linha.

Arquivo de entrada:

5414444444 87654873234  88888888888
6646666666 54122222222 
54155555558888 54176543235 5416666666

Arquivo de saída:

54149444444 87654873234  88888888888
6646666666 54122222222 
54155555558888 54176543235 54169666666
    
por user180769 21.07.2016 / 11:34

3 respostas

2

Como pode ver no exemplo OP, significa word não a string so

sed 's/\b541./&9/g' file

Se o 541 puder começar de outro lugar na palavra (não do começo)

sed 's/\b\S*541/\n&/g     #mark a beginning of word(s) with pattern
     s/\n\(....\)//g   #remove mark and do adding
    ' file

Você pode limitar a quantidade de símbolos da (s) palavra (s) como segue

sed 's/\b\(541.\)\(\S\{6\}\)\b//g' file

ou mais geral

sed 's/\b541./&\n/g;s/\n\S\{6\}\b/9&/g;s/\n//g' file
    
por 21.07.2016 / 11:49
1

Você poderia usar perl

perl -lane 'map{length==10&&/^541/&&s/.{4}/$&9/}@F;print join(" ",@F)' file

Use o mapa para executar verificações e submarinos em cada campo. Em seguida, imprime a matriz de campos unidos por um único espaço (assim, a formatação será afetada se não houver espaços únicos consistentes entre os campos)

ou apenas usando regex

perl -lane 'map{s/^541.\K.{6}$/9$&/}@F;print join(" ",@F)' file

Saída:

54149444444 87654873234 88888888888
6646666666 54122222222
54155555558888 54176543235 54169666666
    
por 21.07.2016 / 12:32
1

Portável:

sed '
  s/.*/ & /; # add a leading and trailing space
  :1
    s/\([[:blank:]]541[^[:blank:]]\{2\}\)\([^[:blank:]]\{5\}[[:blank:]]\)//g
    # replace in a loop until there is no more match
  t1
  # remove the blanks we added earlier:
  s/^ //;s/ $//'

Você pode evitar a adição temporária dos espaços à esquerda e à direita procurando a ocorrência dessa sequência não em branco no início ou no final da lista, além de seguir / antes de um espaço em branco. Isso pode ser feito POSIXly com um regexp, mas isso é um pouco complicado:

sed '
  :1
    s/^\(\(.*[[:blank:]]\)\{0,1\}541[^[:blank:]]\{2\}\)\([^[:blank:]]\{5\}\([[:blank:]].*\)\{0,1\}\)$//
  t1'

Com perl , usando operadores de look-around:

perl -lpe 's/((?<!\H)541\H\H)(\H{5})(?!\H)/${1}9$2/g'

Ou processando palavras uma por uma:

perl -lpe 's{\H+}{$&=~s/^541..\K.{5}$/9$&/r}ge'

( \K e o sinalizador de substituição r exigem uma versão relativamente recente de perl ).

    
por 21.07.2016 / 12:40