2

2 つの文字列変数を比較し、両方で同じ文字を出力したいと考えています。commこれを行う方法がよくわかりません。 orを使用することを考えてdiffいましたが、一致する文字のみを出力するための正しいパラメーターがよくわかりません。また、ファイルを取り込むと言い、これらは文字列です。誰でも助けることができますか?

入力:

a=$(echo "abghrsy")
b=$(echo "cgmnorstuvz")

出力:

"grs"
4

4 に答える 4

2

$a変数を割り当ててシェルするためにそれほど多くの作業を行う必要はありません$b。ただ...

a=abghrsy
b=cdgmrstuvz

さて、最長共通サブシーケンス1と呼ばれる古典的なコンピュータ サイエンスの問題があり、これはあなたの問題に似ています。

ただし、一般的な文字だけが必要な場合は、Ruby に作業を任せる方法があります...

$ ruby -e "puts ('$a'.chars.to_a & '$b'.chars.to_a).join"

1. 別の最長共通部分文字列問題と混同しないでください。

于 2013-04-06T04:32:35.167 に答える
1

gnu coreutils を使用 (@DigitalRoss に触発)。

a="abghrsy"
b="cgmnorstuvz"

echo "$(comm -12 <(echo "$a" | fold -w1 | sort | uniq) <(echo "$b" | fold -w1 | sort | uniq) | tr -d '\n')"

印刷されますgrs。ユニークな文字だけが必要だと思いました。

更新: ダッシュ用に変更..

 #!/bin/dash

 string1=$(printf "$1" | fold -w1 | sort | uniq | tr -d '\n');
 string2=$(printf "$2" | fold -w1 | sort | uniq | tr -d '\n');

 while [ "$string1" != "" ]; do
   c1=$(printf '%s\n' "$string1" | cut -c 1-1 )
   string2=$(printf "$2" | fold -w1 | sort | uniq | tr -d '\n');
   while [ "$string2" != "" ]; do
     c2=$(printf '%s\n' "$string2" | cut -c 1-1 )
     if [ "$c1" = "$c2" ]; then
       echo "$c1\c"
     fi
     string2=$(printf '%s\n' "$string2" | cut -c 2- )
   done
   string1=$(printf '%s\n' "$string1" | cut -c 2- )
 done
 echo;

注:私は初心者です。これを行うためのより良い方法があるかもしれません。

于 2013-04-06T04:47:33.583 に答える
1

良い質問+1。

awk トリックを使用してこれを行うことができます。

a=abghrsy
b=cdgmrstuvz
comm -12 <(echo $a|awk -F"\0" '{for (i=1; i<=NF; i++) print $i}') <(echo $b|awk -F"\0" '{for (i=1; i<=NF; i++) print $i}')|tr -d '\n'

出力:

grs

これを使用するとawk -F"\0"、入力文字列が 1 文字ずつ異なる awk フィールドに分割されることに注意してください。Rest は、 と を非常に簡単に使用commtrます。

PS:入力文字列がソートされていない場合は、awk の出力をパイプしてソートするか、awk 内で配列のソートを行う必要があります。

更新: awk のみのソリューション (comm なし):

echo "$a;$b" | awk -F"\0" '{scnd=0; for (i=1; i<=NF; i++) {if ($i!=";") {if (!scnd) arr1[$i]=$i; else if ($i in arr1) arr2[$i]=$i} else scnd=1}} END { for (a in arr2) printf("%s", a)}'

これは、文字列にセミコロンが含まれていないことを前提としています (そうでない場合は、他の文字を使用できます)。

更新 2: 最も簡単な解決策は grep -o を使用することだと思います

(@CodeGnomeからの回答に感謝)

echo "$b" | grep -o "[$a]" | tr -d '\n'
于 2013-04-06T05:36:06.727 に答える
1

GNU Grep で文字クラスを使用する

これは広く適用できるソリューションではありませんが、特定のユース ケースには非常に適しています。アイデアは、最初の変数を文字クラスとして使用して、2 番目の文字列と照合することです。例えば:

a='abghrsy'
b='cgmnorstuvz'
echo "$b" | grep --only-matching "[$a]" | xargs | tr --delete ' '

これはgrs期待どおりに生成されます。xargstrの使用は、出力から改行とスペースを削除するだけであることに注意してください。必要に応じて、これを別の方法で処理することもできます。

交差点を設定

ただし、本当に探しているのは、設定された交差点です。シェルで「ウィング」することもできますが、Ruby、Python、Perl などの言語を使用した方がよいでしょう。

Ruby ワンライナー

既存のシェル スクリプトと統合する必要がある場合は、現在のスクリプト内で Bash 変数を使用するシンプルな Ruby ワンライナーを次のように呼び出すことができます。

a='abghrsy'
b='cgmnorstuvz'
ruby -e "puts ('$a'.split(//) & '$b'.split(//)).join"

Ruby スクリプト

代わりにすべてを Ruby で行うことで、確かに物事をよりエレガントにすることができます。

string1_chars = 'abghrsy'.split //
string2_chars = 'cgmnorstuvz'.split //
intersection  = string1_chars & string2_chars
puts intersection.join

これは確かに私には読みやすく堅牢に思えますが、あなたのマイレージは異なる場合があります. 少なくとも今は、選択できるオプションがいくつかあります。

于 2013-04-06T06:13:32.900 に答える