shell - 两个字符串中包含的字符 - 已编辑

时间:2013-04-06 04:21:26

标签: shell unix dash-shell

我想比较两个字符串变量并打印两者相同的字符。我不确定如何做到这一点,我想使用commdiff,但我不确定正确的参数只打印匹配的字符。他们也说他们收录文件,这些都是字符串。有人可以帮忙吗?

输入:

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

输出:

"grs"

4 个答案:

答案 0 :(得分:2)

您无需做太多工作来分配$a$b shell变量,您可以......

a=abghrsy
b=cdgmrstuvz

现在,有一个名为longest common subsequence1的经典计算机科学问题与你的类似。

但是,如果你只想要常用字符,那么有一种方法可以让Ruby完成工作......

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

1。不要与不同的longest common substring problem.

混淆

答案 1 :(得分: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。我以为你只想要uniq字符。

<强>更新 修改为短划线..

 #!/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;

注意:我只是一个初学者。可能有更好的方法来做到这一点。

答案 2 :(得分: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"将字符输入字符串分解为不同的awk fiedls。休息非常直接使用commtr

PS:如果您输入的字符串未排序,那么您需要管道awk的输出来排序或在awk中对数组进行排序。

更新:awk only解决方案(没有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'

答案 3 :(得分:1)

使用GNU Grep的字符类

这不是一个广泛适用的解决方案,但它非常适合您的特定用例。我们的想法是使用第一个变量作为字符类来匹配第二个字符串。例如:

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

这会产生grs,如你所料。请注意,使用 xargs tr 只是为了从输出中删除换行符和空格;如果你愿意,你当然可以用其他方式处理这个问题。

设置交叉点

你真正想要的是一个集合交叉点。虽然你可以在shell中“翼”,但最好还是使用像Ruby,Python或Perl这样的语言来实现这一目标。

Ruby One-Liner

如果需要与现有的shell脚本集成,可以在当前脚本中调用使用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

这对我来说似乎更具可读性和稳健性,但您的里程可能会有所不同。至少现在你有一些选择可供选择。