打印文件中未排序字符串之间的差异
Print differences between not sorted strings from files
我有两个包含 n 行的文件,每行有一个字符串。我想打印出这些列表之间的字符差异。您可以将操作想象成一种 "Subtraction" 字母。它应该是这样的:
List1 List2 Result
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb
这意味着第二个列表没有按字母顺序排序,但是要删除的所有子字符串都在每个字符串中排序(Aa
在 Bb
之前在 Cc
之前)。请注意,要删除的元素可以是 1 或 2 个字符长(Aa
或 F
),始终以大写字母开头,后跟(有时)小写字母。这些字符串完全由几个 "elements" 的排列组成,例如 Aa
、Bb
、Cc
、Dd
、E
、F
, Gg
, ...等等。
这个问题在这里以非常相似的形式得到了回答:
Bash script Find difference between two strings,
但仅适用于手动输入的两个字符串,而我需要进行数百次操作。我正在努力将文件实现为该命令的源,同时还要正确分隔字符。这是我的改编:
split_chars() { sed $'s/./&\\n/g' <<< ""; }
comm -23 <(split_chars AaBbCcDd) <(split_chars AaCcDd)
输出
B
b
所以即使在这种情况下,仍然不是我想要的。我想 split_chars
命令是这里的关键,但我无法以任何方式将它应用到我的文件中。将文件名放在括号内显然不起作用。
作为参考,一个简单的
commm -23 List1 List2
只是导致
AaBbCcDd
AaBbCcEe
AaBbCcF
comm: file 2 is not in sorted order
由于您不想拆分字符而是拆分以大写字母开头的子字符串,因此您应该将 split_chars
替换为以下函数。
split() { sed 's/[A-Z]/\n&/g' <<< ""; }
可以通过使用 tr -d \n
.
删除所有换行符来撤消拆分行的操作
要从另一个行列表中减去一个行列表,您可以使用 grep
而无需排序。
grep -vFxf subtrahend minuend
这将按原始顺序打印文件 minuend
中不在文件 subtrahend
.
中的那些行
要将所有内容放在一起,您必须
- 并行逐行读取两个文件
- 将每个字符串拆分成一个行列表
- 减去那些列表
- 撤消拆分
这是一个简化版本,假设您的输入文件仅包含所描述格式的行并且具有相同的长度。
split() { sed 's/[A-Z]/\n&/g' <<< ""; }
subtract() { grep -vFxf "" ""; }
union() { tr -d \n; echo; }
paste List1 List2 | while read -r minuend subtrahend; do
subtract <(split "$minuend") <(split "$subtrahend") | union
done
Bash 带有循环的脚本很慢。如果您需要更快的解决方案,您应该使用更高级的语言重写此脚本,例如 perl
或 python
.
GNU awk 中的另一个:
$ gawk 'NR==FNR {
a[FNR]=[=10=]
next
}
{
patsplit([=10=] a[FNR],b,/[A-Z][a-z]?/)
printf "%s%s%s", a[FNR],OFS,[=10=]
for(i in b)
if(!(match([=10=],b[i])&&match(a[FNR],b[i])))
printf "%s%s", OFS, b[i]
print ""
}' file1 file2
输出:
List1 List2
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb
我有两个包含 n 行的文件,每行有一个字符串。我想打印出这些列表之间的字符差异。您可以将操作想象成一种 "Subtraction" 字母。它应该是这样的:
List1 List2 Result
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb
这意味着第二个列表没有按字母顺序排序,但是要删除的所有子字符串都在每个字符串中排序(Aa
在 Bb
之前在 Cc
之前)。请注意,要删除的元素可以是 1 或 2 个字符长(Aa
或 F
),始终以大写字母开头,后跟(有时)小写字母。这些字符串完全由几个 "elements" 的排列组成,例如 Aa
、Bb
、Cc
、Dd
、E
、F
, Gg
, ...等等。
这个问题在这里以非常相似的形式得到了回答: Bash script Find difference between two strings, 但仅适用于手动输入的两个字符串,而我需要进行数百次操作。我正在努力将文件实现为该命令的源,同时还要正确分隔字符。这是我的改编:
split_chars() { sed $'s/./&\\n/g' <<< ""; }
comm -23 <(split_chars AaBbCcDd) <(split_chars AaCcDd)
输出
B
b
所以即使在这种情况下,仍然不是我想要的。我想 split_chars
命令是这里的关键,但我无法以任何方式将它应用到我的文件中。将文件名放在括号内显然不起作用。
作为参考,一个简单的
commm -23 List1 List2
只是导致
AaBbCcDd
AaBbCcEe
AaBbCcF
comm: file 2 is not in sorted order
由于您不想拆分字符而是拆分以大写字母开头的子字符串,因此您应该将 split_chars
替换为以下函数。
split() { sed 's/[A-Z]/\n&/g' <<< ""; }
可以通过使用 tr -d \n
.
要从另一个行列表中减去一个行列表,您可以使用 grep
而无需排序。
grep -vFxf subtrahend minuend
这将按原始顺序打印文件 minuend
中不在文件 subtrahend
.
要将所有内容放在一起,您必须
- 并行逐行读取两个文件
- 将每个字符串拆分成一个行列表
- 减去那些列表
- 撤消拆分
这是一个简化版本,假设您的输入文件仅包含所描述格式的行并且具有相同的长度。
split() { sed 's/[A-Z]/\n&/g' <<< ""; }
subtract() { grep -vFxf "" ""; }
union() { tr -d \n; echo; }
paste List1 List2 | while read -r minuend subtrahend; do
subtract <(split "$minuend") <(split "$subtrahend") | union
done
Bash 带有循环的脚本很慢。如果您需要更快的解决方案,您应该使用更高级的语言重写此脚本,例如 perl
或 python
.
GNU awk 中的另一个:
$ gawk 'NR==FNR {
a[FNR]=[=10=]
next
}
{
patsplit([=10=] a[FNR],b,/[A-Z][a-z]?/)
printf "%s%s%s", a[FNR],OFS,[=10=]
for(i in b)
if(!(match([=10=],b[i])&&match(a[FNR],b[i])))
printf "%s%s", OFS, b[i]
print ""
}' file1 file2
输出:
List1 List2
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb