文字列インスタンスの範囲を変更する方法

文字列インスタンスの範囲を変更する方法

テキストファイルの各行にある部分文字列の一部のインスタンスを変更する必要があります。これらのインスタンスはすべて連続的です(例:3〜6または2〜5など)。このタスクにはどのようなコマンドが必要ですか?私が得た最も近いものは次のとおりです。

sed 's/this/that/3' file1

これは3回目だけ状況を変えます。同じことがあってほしい

sed 's/this/that/3,6' file1

答えかもしれませんが、sed範囲は表示されません。

入力例:

I want to change all letters "a" to "w" starting from the word "all" until the second "all" (inclusive)

予想出力:

I want to change wll letters "w" to "w" stwrting from the word "wll" until the second "all" (inclusive)

答え1

そしてperl

3番目から6番目のasをsに変更しますb

$ echo aaaaaaaaa | perl -pe '$n=0; s{a}{++$n;$n==3..$n==6?"b":$&}ge'
aabbbbaaa

これは演算子eのフラグを使用するため、置換はs{regex}{replacement}flagsコードとして評価されます。これは、インクリメントされ"b"たカウンタが3から6の間で提供され、$&それ以外の場合は一致する値()が提供されます。または:

$ echo aaaaaaaa | perl -pe '$n=0; s/a(?(?{++$n; $n == 3 .. $n == 6})|(*FAIL))/b/g'
aabbbbaa

増加するカウンタが3〜6の範囲にない場合は、情報を(?(condition)yes|no)提供する正規表現演算子を使用してください。(*FAIL)

GNUは3番目それ以降のアイテムの交換をsedサポートしています。s/foo/bar/3gfoo

したがって、次の固定文字列の場合は、次のようにします。

$ echo aaaaaaaaa | sed 's/a/\n/3g;s/\n/a/5g;s/\n/b/g'
aabbbbaaa

つまり、最後の改行文字aから3番目の文字を改行文字に置き換え(パターンスペースで他の状況が発生しないように)、最後の改行文字から5番目の文字をs(6 - 3 + 1 = 4)に戻します。 。必要なas)の数aに応じて、次の項目を復元してから、残りのb改行をすべてsに置き換えます。

何でもsed:

sed 's/a/\
/g
s/\n/b/3
s/\n/b/3
s/\n/b/3
s/\n/b/3
s/\n/a/g'

最初の 2 つの発生の間の s をas に変更するには、次のようにします。wall

$ echo aaallaaallaaa | perl -pe 's{all.*?all}{$& =~ s/a/w/gr}e'
aawllwwwllaaa

\ball分離が必要な場合は、単語境界演算子を使用してください。性格

$ echo 'alloy (all-hands aaa ball all) fall' | perl -pe 's{all.*?all}{$& =~ s/a/w/gr}e'
wlloy (wll-hands aaa ball all) fall
$ echo 'alloy (all-hands aaa ball all) fall' | perl -pe 's{\ball\b.*?\ball\b}{$& =~ s/a/w/gr}e'
alloy (wll-hwnds www bwll wll) fall

-Mopen=localeASCIIのみと仮定するのではなく、ロケール文字マップに従ってデコードする文字を追加します。たとえば、alléeフランス語の単語をUTF-8にエンコードし、all後に単語以外の文字が続きません。)

答え2

ではこれは不可能かもしれませんが、sed次のGNUawkプログラムはうまくいきます:

awk -v frst=2 -v lst=5 '{for (i=1; i<=(lst-frst+1);i++) $0=gensub(/a/,"w",frst)}1'
  • これにより、最初と最後の項目が置き換えられる変数frstsumに渡されます。lstawk
  • 次に、行内の検索パターンの-番目の発生をgensub()置き換え、結果を現在の行バッファに再割り当てするために使用されます。frst
  • lst-frst+1必要なすべてのイベントを置き換えるために合計()回実行されます。次に、現在の行を印刷します(すべての修正を含む)。
  • 置き換えられたアイテムは次のループ反復に含まれなくなり、置換される文字列内のアイテムの数は常に変わりません。

適用例:

$ echo "a1a2a3a4a5a6" | awk -v frst=2 -v lst=5 '{for (i=1; i<=(lst-frst+1);i++) $0=gensub(/a/,"w",frst)}1'
a1w2w3w4w5a6

またはテキスト:

$ echo 'I want to change all letters "a" to "w" starting from the word "all" until the second "all" (inclusive)' | awk -v frst=3 -v lst=6 '{for (i=1; i<=(lst-frst+1);i++) $0=gensub(/a/,"w",frst)}1'
I want to change wll letters "w" to "w" stwrting from the word "wll" until the second "all" (inclusive)

いつものように、検索パターンが重複する可能性がある場合、期待どおりに動作しません。

答え3

いくつかの奇妙な場合:

awk -v FS='a' -v start=3 -v end=6 -v replace="w" '
{
  for(i=1; i<NF; i++)
      printf("%s", $i (start<=i && i<=end? replace: FS))
  print $NF
}' infile

ここではFS=aawk に文字に基づいてレコードを分割するよう指示し、a他の awk 変数も次のように定義します。スタート終わりそして変えるはそれぞれターゲット文字「a」の開始位置と終了位置であり、これを「w」文字に置き換えます。

その後、フィールドを繰り返し、フィールド自体を印刷します。フィールド番号が始点と終点の間にある場合はフィールド自体を印刷し、そうでない場合は文字「a」を印刷します。最後に最後のフィールドも出力します。

コードスニペットの実行

答え4

使用幸せ(以前のPerl_6)

~$ echo aaaaaaaa | perl6 -pe 's:nth(3..6)/a/b/;'
aabbbbaa

Raku (Perl 系列のプログラミング言語) には、等の同義語をnthサポートする新しい正規表現修飾子 ("位置副詞") があります。一般的な代替目的のために、数値または範囲引数を挿入します。1st2nd3rdnth()

上記のバージョンはクイックバージョンです。これは、Rakuの正規表現修飾子がどのように直感的であるかを示すためのものです(テーマ変数を再ロードするために使用されるたびに、、の6th一致5th4th連続3rd的に置き換えられます)。andthen$_

~$ echo aaaaaaaa | perl6 -ne 'S:6th/a/b/ andthen S:5th/a/b/ andthen S:4th/a/b/ andthen S:3rd/a/b/ andthen .put;'
aabbbbaa

https://docs.raku.org/言語/regexes#Positional_adverbs
https://raku.org

関連情報