我的问题是通过 shell 脚本确定某些字符串是否是彼此的排列,例如
1.Nf3 c5 2.e4 Nc6
1.e4 c5 2.Nf3 Nc6
正如您所看到的,排列是基于原子子串的。换句话说,我想知道两个字符串是否包含相同的子字符串而不考虑顺序。
AWK 是一种专为高级文本处理而设计的编程语言。因此出现的一个想法是将两个字符串拆分为数组:
{1., Nf3, c5, 2., e4, Nc6}
{1., e4, c5, 2., Nf3, Nc6}
并比较两者是否包含相同的元素。但我不确定这是否适合 awk 方式。
第二种方法是将第一个字符串拆分为模式{1., Nf3, c5, 2., e4, Nc6}
,并在第二个字符串中搜索所有模式,并根据这些匹配创建一个新字符串。毕竟我可以检查新字符串是否等于第一个字符串。 awk 中还有其他方法用于这种特定的文本处理吗?
答案1
我认为awk
这不是正确的方法。只需分割字符串,对字符串元素进行排序,然后比较结果即可。
示例bash
:
$ split_and_sort() { sed -r 's/\</\n/g' | sort; }
$ split_sort_and_compare() {
if [ "$(split_and_sort <<< "$1")" = "$(split_and_sort <<< "$2")" ]
then echo "Match"
else echo "No match"
fi
}
$ split_sort_and_compare "1.Nf3 c5 2.e4 Nc6" "1.e4 c5 2.Nf3 Nc6"
Match
$ split_sort_and_compare "1.Nf3 c5 2.e4 Nc6" "1.e4 c5 2.Nf3 Nc5"
No match
这只是一个粗略的例子来说明我的想法,以及我自己对如何分割和比较字符串的解释。根据您的规则制作您自己的更复杂的功能。
答案2
仅供记录,这是一个 awk 解决方案(虽然不是很棘手),以防您需要将此解决方案集成到任何现有的 awk 项目中。
a="1.Nf3 c5 2.e4 Nc6"
b="1.e4 c5 2.Nf3 Nc6"
awk 'BEGIN{FS=""}{last=NF;for (i=1;i<=NF;i++) {if (NR==FNR) {a[i]=$i} else {b[i]=$i}}} \
{asort(a);asort(b)}END{{for (k=1;k<=last;k++) if (a[k]!=b[k]) nomatch++}{print (nomatch==0)?"match":"no match"}}' <(echo "$a") <(echo "$b")
如果你只是想比较这两个字符串,我会使用一些 bash 方式,或者像 xhienne 建议的答案,甚至像这样:
[[ $(sort <(grep -o . <<<"$a") |base64) == $(sort <(grep -o . <<<"$b") |base64) ]] && echo "match" || echo "differ"
在这两种情况下,逻辑是相同的。输入字符串按字符拆分,然后一一排序,并对这两个排序的字符串进行比较。
在上面的bash方式中,我想将排序后的字符串编码为base64并比较它们的base64值。
答案3
检查两个字符串是否包含相同字符的另一种方法是计算它们的 ASCII 值之和。
$ while read -rn1 char;do sumA+=$(printf '%d+' "'$char'");done <<<"1.Nf3 c5 2.e4 Nc6"
$ while read -rn1 char;do sumB+=$(printf '%d+' "'$char'");done <<<"1.e4 c5 2.Nf3 Nc6"
$ echo "$sumA"
49+46+78+102+51+39+99+53+39+50+46+101+52+39+78+99+54+39+
$ echo "$sumB"
49+46+101+52+39+99+53+39+50+46+78+102+51+39+78+99+54+39+
$ bc <<<"${sumB:0:-1}"
1114
$ bc <<<"${sumA:0:-1}"
1114
相同的数字和 = 相同的字符串。因此,通过比较这两个 bc 值,您可以得到匹配/不匹配条件。
如果字符串之间的一个字符不同,则 ascii 值之和将会不同:
$ while read -rn1 char;do sumC+=$(printf '%d+' "'$char'");done <<<"1.Nf3 q5 2.e4 Nc6" #q5 is different than string A
$ echo "$sumC"
49+46+78+102+51+39+113+53+39+50+46+101+52+39+78+99+54+39+
$ bc <<<"${sumC:0:-1}"
1128