部分文字列のみ変更

部分文字列のみ変更

STARTパターンで表示されたセクションの前後に無効なテキストがあるファイルEND(各特定の文字列は一度だけ表示され、同じ行に正しい順序で表示されます)。私はただSTARTの間の部分に対して文字列操作をしたいと思います。END

入力例:

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

- 操作に関する限り、および間sedの部分文字列(および部分文字列のみ)は、私が使用するように変更する必要があります。STARTENDsed 's/_this_// ; s/modi/MODI/ ; y/as/45/'

出力例:

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複数の値を異なる場所に設定できないFS="START|END"ため失敗します。OFS

入れ子になったコマンドの置き換えと他の区切り文字()を試してみましたが、失敗し、コマンドの前後に文字があり、コマンドを混乱させる可能性があることもsed懸念していました(例:a)。~アイデアは、「内部」部分文字列のみを選択して操作を実行し、それを代替の一部として使用することです。STARTEND/

sed "s/^\(.*\)START.*END\(.*\)$/\1$(sed 's~^.*START~~
                                         s~END.*~~
                                         s~_this_~~
                                         s~modi~MODI~
                                         y~as~45~' infile)\2/" infile

私は例えばperl....しかし、何でも慣れていません。

sedREGEX一致サブストリング行にのみセット操作を適用する方法はありますか?

答え1

perl -CSD -ne '
    if (my ($before, $between, $after) = /^(.*START)(.*)(END.*)/) {
        s/_this_//, s/modi/MODI/, tr/as/45/ for $between;
        print "$before$between$after\n";
    } else { print; }' -- file
  • -CSDUTF-8で入力をデコードし、出力をUTF-8にエンコードします。
  • $before代わりに、およびを使用して3つの変数、およびを埋めることができますが、$betweenより良い解決策を見つけることができませんでした。 $after/p${^PREMATCH}${^POSTMATCH}
    if (my ($s) = /START(.*)END/p) {
        s/_this_//, s/modi/MODI/, tr/as/45/ for $s;
        print "${^PREMATCH}START${s}END${^POSTMATCH}";
    } else { print; }
    

START ... END部分を1行で繰り返すことができる場合は、各行を繰り返す必要があります。

for my $part (split /(START.*?END)/) {
    if ($part =~ /^START.*END$/) {
        s/_this_//, s/modi/MODI/, tr/as/45/ for $part;
    }
    print "$part";
}

答え2

基準を使用しsed、各行に正確に1つと1つSTARTの部分END文字列が含まれているとします(順番に)。

# Skip (pass through) lines that does not have START followed by END.
/.*START\(.*\)END.*/ !b

# Save the original line in the hold space.
h

# Remove the start and the end from the line.
# This leaves the bit of the line that we want to modify.
# (This reuses the previous regular expression.)
s//\1/

# Modify what's left.
s/_this_//
s/modi/MODI/
y/as/45/

# Append the original line from the hold space,
# with a newline as delimiter.
G

# Move the modified bit into the correct spot with a substitution,
# while deleting the old substring between START and END.
s/\(.*\)\n\(.*START\).*\(END.*\)/\2\1\3/

テスト:

$ cat file
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
$ sed -f script file
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

インライン、コマンドラインから:

sed -e '/.*START\(.*\)END.*/!b' -e h -e 's//\1/' \
    -e 's/_this_//' -e 's/modi/MODI/' -e 'y/as/45/' \
    -e G -e 's/\(.*\)\n\(.*START\).*\(END.*\)/\2\1\3/' file

答え3

いつでも独自のOFSを複数構築できます。

awk -v FS='START|END' -v OFS= -v map='_this_\r\rmodi\rMODI\ra\r4\rs\r5' '
  BEGIN{ split(FS, mOFS, "|") }
  { n=split(map, tr, "\r"); for(i=1; i<n; i+=2) gsub(tr[i], tr[i+1], $2);
  print $1, mOFS[1], $2, mOFS[2], $3
}' infile

gsub() の最初の引数は正規表現なので、定義時に注意してください。map=....;右マッピングには、&逆参照\1などの一部の特殊文字があってはなりません。ただし、マッピングを手動で作成するときに特殊文字をエスケープして、gsub()によって排他的に解釈されるのを防ぐことができます。

CRを使用して\r地図を分離しています。あなたが言ったように、入力ファイルに存在しない唯一のものです。ただし、\0Split()とawkの他の関数(または他のプログラミングでは機能しません)言語も同じです\0。したがって、各左正規表現tr[i](ここでは文字列)が配列の次のtr[i+1]右正規表現に置き換えられますtr

このアプローチを使用すると、ペアごとに複数のgsub()を作成する必要がなくなります。

答え4

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ cat tst.awk
match($0,/START.*END/) {
    tgt = substr($0,RSTART+5,RLENGTH-8)
    sub(/_this_/,"",tgt)
    sub(/modi/,"MODI",tgt)
    gsub(/a/,"4",tgt)
    gsub(/s/,"5",tgt)
    $0 = substr($0,1,RSTART+4) tgt substr($0,RSTART+RLENGTH-3)
}
{ print }

$ awk -f tst.awk file
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

関連情報