Em um arquivo que tenha algum texto ilegível antes e depois de uma seção marcada por padrões START
e END
(strings específicas que ocorrem apenas uma vez cada e na ordem correta e na mesma linha). Eu gostaria de fazer alguma manipulação de string SOMENTE na parte entre START
eEND
Exemplo de entrada:
aomodi3hriq32| ¶³r 0q93aoiSTART_this_is_to_be_modified_ENDaqsdofuha23uru| ²23i ii3uhfia
oawpo3<9"§ A hSTART_this_also_needs_modification_ENDqa 032/a237(°1Q"§ >A_this_
START changeme ENDnot_this_modias
Em termos de sed
-operações, a substring (e apenas a substring) entre START
e END
deve ser modificada como se eu usasse sed 's/_this_// ; s/modi/MODI/ ; y/as/45/'
.
Saída de exemplo:
aomodi3hriq32| ¶³r 0q93aoiSTARTi5_to_be_MODIfied_ENDaqsdofuha23uru| ²23i ii3uhfia
oawpo3<9"§ A hSTART4l5o_need5_MODIfic4tion_ENDqa 032/a237(°1Q"§ >A_this_
START ch4ngeme ENDnot_this_modias
awk
com FS="START|END"
falha, pois OFS
não pode ser definido para vários valores em posições diferentes.
Eu tentei usar sed
com uma substituição de comando aninhada e separadores diferentes ( ~
), mas falhei e também temo que possa haver caracteres antes START
/ depois END
que mexam com o comando (por exemplo, a /
). A ideia era selecionar apenas a substring "interna" e fazer as operações e usá-la como parte da substituição:
sed "s/^\(.*\)START.*END\(.*\)$/\1$(sed 's~^.*START~~
s~END.*~~
s~_this_~~
s~modi~MODI~
y~as~45~' infile)\2/" infile
Eu não estou familiarizado com, por exemplo perl
.... mas o que for preciso.
Existe alguma maneira de fazer com que um conjunto de sed
-operações se aplique apenas a uma substring correspondente a REGEX de uma linha?
-CSD
decodifica a entrada de UTF-8 e codifica a saída para UTF-8$before
,$between
, e$after
, poderíamos ter usado/p
com${^PREMATCH}
and${^POSTMATCH}
, mas não acho a solução mais agradável:Se as partes START...END puderem ser repetidas em uma única linha, você precisará fazer um loop em cada linha.
Usando padrão
sed
e assumindo que cada linha contém exatamente umaSTART
e umaEND
substring (nessa ordem):Teste:
Em linha, na linha de comando:
Talvez com
awk
e funções de string:Você sempre pode construir seu próprio OFS múltiplo:
note que o primeiro argumento do gsub() é o regex, então cuidado ao definir o
map=....
; também não deve haver alguns caracteres especiais para seu mapeamento à direita, como Ì&
back-references\1
, etc; no entanto, como você está escrevendo o mapeamento manualmente, você pode escapar quaisquer caracteres especiais para evitar que eles sejam interpretados especialmente pelo gsub().Eu usei CR
\r
para separar o mapeamento como você mencionou que é a única coisa que não existirá em seu arquivo de entrada ao lado do\0
qual isso não pode ser usado em split() e outras funções em awk (ou talvez em outras linguagens de programação também) como awk irá apenas considere o máximo que\0
pode existir dentro de uma string. portanto, cada regex à esquerdatr[i]
(strings aqui) será substituída pela próxima à direitatr[i+1]
datr
matriz.usar esta forma irá evitar que você escreva vários gsub() para cada par.
Este GNU
sed
dá o resultado desejadoUsando qualquer awk em qualquer shell em cada caixa Unix:
Apresento uma solução que também irá
restrição : suponho que seu arquivo não use 4 caracteres, escolhi o 'frequentemente não utilizado' "\001" a "\004" (mas quaisquer outros 4 caracteres não utilizados podem ser usados)
(como eu uso: \001 para fazer qualquer END começar com uma nova linha e qualquer END terminar com uma nova linha, forçando qualquer outra combinação que não seja "START(nonSTARTnorEND)END" a estar em linhas separadas e, portanto, não considerada. e eu uso \ 004 para "salvar" as novas linhas do arquivo original e recuperá-las no final. E eu uso \002 para representar um START, \003 para representar um END, permitindo-me verificar se não há nenhum desses entre também (e que Começo com START e termino com END quando procuro as strings a serem substituídas.) Todas essas coisas são permitidas por causa dessas substituições.
Alguém poderia fazer:
nota: isso pode ser ainda mais simplificado (não é necessário substituir START por \002 nem terminar por \003, eu fiz isso primeiro para poder usar :
[^\002\003]*
para garantir que a string intermediária também não contenha, mas o \001-> \n garante que já...)Você pode fazer o que estava tentando, desde que tenha GNU sed com o sinalizador /e no comando s///:
O acima pode ser dividido em funções para torná-lo mais limpo. Aqui definimos funções auxiliares e variáveis para desorganizar:
Com Perl , isso vem naturalmente:
Ou, POSIXly podemos particionar o espaço do molde em 3 partes, armazenar em espera, então transformar a parte do meio e costurá-las de volta.