Sed:テキスト内のすべての単語の最初の単語以外のすべての単語の繰り返しを修正します。

Sed:テキスト内のすべての単語の最初の単語以外のすべての単語の繰り返しを修正します。

同様の作業を行うにはsedを使用する必要がありますか?

qq    ab xyz     ab qq aa ab 

になる:

qq    ab xyz     +ab+ +qq+ aa +ab+

答え1

入力に<>または+文字がすべて含まれていない場合は、次のことができます。

sed '
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g'

次の場合、いつでもこの問題を回避できます。

sed '
  s/:/::/g;s/</:{/g;s/>/:}/g
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g
  s/:}/>/g;s/:{/</g;s/::/:/g'

これは、各行で独立してこれを実行すると仮定します。フルファイルに対してこれを行うには、まずファイル全体をメモリにロードする必要があります(一部のsed実装にはサイズ制限があります)。

sed '
  :2
  $!{N;b2
  }
  s/:/::/g;s/</:{/g;s/>/:}/g
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g
  s/:}/>/g;s/:{/</g;s/::/:/g'

ただし、これは非常に非効率的で、使いやすくなりますperl

perl -pe 's/\w+/$seen{$&}++ ? "+$&+" : $&/ge'

ラインベース:

perl -pe 'my %seen;s/\w+/$seen{$&}++ ? "+$&+" : $&/ge'

答え2

別のアプローチは次のとおりです。これはいくつかのsedsを使用します。

an='[:alnum:]' esc=$(printf '\033\[')
sed "/[${an}]/!d;=;a\ }
    s/.*/ & /;s/[^${an}]\{1,\}/   /g
    s| \([${an}"']\{1,\}\) | \
    s/\\([^+'"${an}"']\\)\\(\1\\)\\([^+'"${an}"']\\)/\\1+\\2+\\3/2|g
' <text |
sed '/^ /!N;s/\n */{/' |
sed -e 's/.*/ & /;s/+/ & /g' \
    -f - \
    -e "s/ //;s/ $//
        s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
        s/ + /+/g" text

基本的に、最初の2つのsedチームは一緒に協力して3番目のスクリプトを作成しました。最初は、sed各行の英数字以外のすべての項目を消去し、行のない行は完全にスキップします。残りのすべての文字グループに対して代替文を作成し、3 番目の文字は終了します。(ほぼ即座に)スクリプトを読んで解釈してください。

2番目のスクリプトは、sed最初のスクリプトが1行ずつ作成されるため、必要であり、1行に複数のステートメントがある可能性がありますs///。最初は英数字を含む各行の行番号を印刷しますが、3番目の関数コンテキスト内でペアを指定する必要があるため、2番目はsedそうします。

以下はスクリプトの例です。

...
43{
    s/\([^+[:alnum:]]\)\(n\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(N\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(G\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }
44{
    s/\([^+[:alnum:]]\)\(b\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(block\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }
45{
    s/\([^+[:alnum:]]\)\(END\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(SEDSCRIPT\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }

2それぞれに末尾がありますs///。これは、各置換が各パターンの第2の発生に対するものであるからである。 2番目の発生が存在しない場合、交換は行われません。上記は私の他のスクリプトで実行した結果です。sed特殊文字や類似文字の影響を受けないようです。

文章を書いて選択項目に色を付けると、何が起こっているのかをより簡単に知ることができます。

s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g

...その行はそうです。コメントを付けたり削除したりすることができます(以前使用していましたが、不要または不要)。

サンプルデータ用に作成するスクリプトは次のとおりです。

1{
    s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(xyz\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(aa\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
 }

印刷される内容は次のとおりです。

qq    ab xyz     +ab+ +qq+ aa +ab+

sedそして私の以前のスクリプトのいくつかは次のとおりです。

        s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${+esc+}0m/g
        s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${+esc+}0m/g
        s/.${bs}//g
        s/\(\(${esc}\)0m\2[^m]*+m+[_ ]\{,+2+\}\)\{+2+\}/_/g
n;      /./!N;G

関連情報