Bashから重複文字を削除する

Bashから重複文字を削除する

行がある場合:

There are seven pencil

次のように印刷したいと思います。

Ther a svn pcil

Bashシェルコマンドとは何ですか?

説明:目標は、複数回出現するすべての文字(最初の文字を除く)を削除することです。

答え1

s/replace-this/with-that/gグローバル置換=すべての発生を意味するsedの古典的な構文に基づいて、誰かがwhich(拡張)の代わりにgwhichを使用できます。2ggglobal replacement but after second occurencegnu sed

削除のみの例e:

$ echo $a
there are seven pencil

$ echo $a | sed 's/e//2g'
ther ar svn pncil

すべての重複文字を削除するには、次のトリックを使用できます。

$ sed -f <(printf 's/%s//2g\n' {a..z}) <<<"$a"
ther a svn pcil

残念ながら、これは機能しません。sed 's/[a-z]//2g'

上記のトリックは、ファイル<( )として使用できるプロセス置換を使用します。

私の解決策では、手続き型置換はsedoption = read sedコマンドを介してファイルから提供されたスクリプトファイルとして扱われます。sed-f

答え2

Awk回避策(大文字と小文字の区別):

s="There are seven pencil"
printf '%s\n' "$s" | awk -v FS="" '{ 
           for(i=1; i<=NF; i++) 
               if ($i==" " || !a[$i]++) printf "%s", $i; print "" 
       }'
  • -v FS=""- 各文字が別々のフィールドになるように「空」フィールド区切り文字を設定します(POSIXではなく多くの実装でサポートされているGNU拡張)。
  • for(i=1; i<=NF; i++)- 文字の繰り返し
  • if ($i==" " || !a[$i]++)- 空白文字または初登場する文字の場合

出力:

Ther a svn pcil

大文字と小文字を区別しないようにするには、a[$i]に置き換えますa[tolower($i)]

答え3

これはBashそのものです。

s="There are seven pencil"
declare -A A
while IFS= read -rn1 a; do
 [ -z "$a" ] || [ -n "${A[$a]}" ] && continue
 printf %s "$a"
 [ "$a" == " " ] || A[$a]=x
done <<<"$s"
echo

1行ずつ説明:

  1. 変数に文字列を割り当てる

    s="There are seven pencil"
    
  2. 連想配列宣言A

    declare -A A
    
  3. これは少し複雑です。ただし、詳細がない場合は、個々の文字ごとに文字列を読み取り、読み取ったばかりの文字をに割り当てますa。これはwhileサイクルです。

    while IFS= read -rn1 a; do
    
  4. 現在の文字が空の場合([ -z "$a" ])または(||)このキー(この文字)に関連する値が設定されている場合(設定されている場合はここに表示されます)、ループを続行します(次の繰り返しに進みます。次の内容をお読みください)。文字)を再印刷せずに続行します)。

    [ -z "$a" ] || [ -n "${A[$a]}" ] && continue
    
  5. 現在の文字を印刷します。

    printf %s "$a"
    
  6. 文字が空白の場合は実行されません。A[$a]=xこれが||ここで意味するものです。A[$a]=x関連タスクです。すべてのスペースを避けるために、配列のキースペースに値を割り当てないでくださいA。 (4番項目参照)

    [ "$a" == " " ] || A[$a]=x
    
  7. これによりwhileサイクルが終了する。<<<"$s"ここに文字列リダイレクトがあります。ループを文字列で埋めます。

    done <<<"$s"
    
  8. 最後に、echo行区切り文字を印刷します。printf5番の項目では文字のみ印刷されます。これがなければ、echo出力は次のシェルプロンプトと同じ行に表示されます。それを脱いで自分で確認してください。

    echo
    

答え4

別のsed解決策:

  • 単一のアルファベット文字の場合:

    $ echo 'here hear' | sed 's/\(\([[:alpha:]]\).*\)\2/\1'
    here ear
    
  • これらのすべてに対してgすでに処理されている文字は再確認されないため、このフラグは役に立ちません。したがって、ループを使用すると、「t」は交換が成功する限りラベルに分岐します。

    $ echo There are seven pencils | sed -e :a -e 's/\(\([[:alpha:]]\).*\)\2/\1/; ta'
    Ther a svn pcil
    

    GNUを使用すると、sed次のように短縮できます。

    sed -E ':a;s/(([[:alpha:]]).*)\2/\1;ta'
    

大文字と小文字を無視(まだGNUを使用sed):

$ echo 'There this That' | sed -E ':a; s/(([[:alpha:]]).*)\2/\1/i; ta'
Ther is a


そのうちperl(ASCII文字はここでのみ):

$ echo 'There are seven pencil' | perl -pe 'while(s/([a-zA-Z]).*?\K\1//g){}'
Ther a svn pcil
$ echo 'There this That' | perl -pe 'while(s/([a-z]).*?\K\1//gi){}'
Ther is a

関連情報