如果可能的话,我想将所有以大写字母开头的单词(不包括行开头的单词)与linux命令结合起来。目标是在这些单词之间创建边缘。 例如:
My friend John met Beatrice and Lucio.
我想要的结果应该是:
我设法通过正则表达式获取所有以大写字母开头的单词,排除行开头的单词。正则表达式是:
*cat gov.json | grep -oP "\b([A-Z][a-z']*)(\s[A-Z][a-z']*)*\b | ^(\s*.*?\s).*" > nodes.csv*
节点设法将它们单独输入到列中,即:
现在的目标是创建以大写字母开头的名称之间可能的组合并将它们放入文件中。有什么建议吗?
如果输出中的对的顺序无关紧要:
$ cat tst.awk
BEGIN { FS="[^[:alpha:]]+"; OFS=", " }
{
for (i=2; i<=NF; i++) {
if ($i ~ /^[[:upper:]]/) {
words[$i]
}
}
}
END {
for (word1 in words) {
for (word2 in words) {
if (word1 != word2) {
print word1, word2
}
}
delete words[word1]
}
}
$ awk -f tst.awk file
Beatrice, Lucio
Beatrice, John
Lucio, John
如果顺序很重要,那么:
$ cat tst.awk
BEGIN { FS="[^[:alpha:]]"; OFS=", " }
{
for (i=2; i<=NF; i++) {
if ($i ~ /^[[:upper:]]/) {
if ( !seen[$i]++ ) {
words[++numWords] = $i
}
}
}
}
END {
for (word1nr=1; word1nr<=numWords; word1nr++) {
word1 = words[word1nr]
for (word2nr=word1nr+1; word2nr<=numWords; word2nr++) {
word2 = words[word2nr]
print word1, word2
}
}
}
$ awk -f tst.awk file
John, Beatrice
John, Lucio
Beatrice, Lucio
在上面,
file
包含原始输入,例如My friend John met Beatrice and Lucio.
这是另一个执行任务的
awk
脚本,在读取输入的同时构建输出。
script.awk
允许重复名称。
BEGIN {FPAT = " [[:upper:]][[:alpha:]]+"}
{
for (i = 1; i <= NF; i++ ) {
for (name in namesArr) {
namePairsArr[pairsCount++] = namesArr[name] $i;
}
namesArr[namesCount++] = $i;
}
}
END {for (i = 0; i < pairsCount; i++) print namePairsArr[i];}
如果不允许重名,
script.awk
是:
BEGIN {FPAT = " [[:upper:]][[:alpha:]]+"}
{
for (i = 1; i <= NF; i++ ) {
if (nameSeenArr[$i]) continue;
nameSeenArr[$i] = 1;
for (name in namesArr) {
namePairsArr[pairsCount++] = namesArr[name] $i;
}
namesArr[namesCount++] = $i;
}
}
END {for (i = 0; i < pairsCount; i++) print namePairsArr[i];}**
奔跑
awk -f script.awk gov.json > nodes.csv
示例输入文件:
My friend John met Beatrice and Lucio
My friend Johna met Beatricea and Lucioa
示例输出:
John Beatrice
John Lucio
Beatrice Lucio
John Johna
Beatrice Johna
Lucio Johna
John Beatricea
Beatrice Beatricea
Lucio Beatricea
Johna Beatricea
John Lucioa
Beatrice Lucioa
Lucio Lucioa
Johna Lucioa
Beatricea Lucioa
当你的结果在数组中时,你可以循环使用
names=( John Beatrice Lucio )
max=${#names[@]}
for ((i1=0; i1<max; i1++)); do
for ((i2=i1+1; i2<max; i2++)); do
echo "${names[$i1]}, ${names[$i2]}"
done
done
当你没有太多名称(长度arglist)时,你可以使用
set -- John Beatrice Lucio
for a; do
shift
for b; do
printf "%s, %s\n" "$a" "$b"
done
done
如果唯一的问题是字符串的第一个单词,我们只需在表达式中添加
.
即可:
.([A-Z][a-z']+)
或者我们将添加一个空格作为左边界:
(\s+)([A-Z][a-z']+)(\s+)?
我们想要的单词在这个捕获组中:
([A-Z][a-z']+)
但是如果我们遇到以下情况,这就会失败:
My friend Alice O'Neal met Beatrice and Lucio
为此我们可以扩展我们想要的输出组。
如果不需要此表达式并且您希望修改它,请访问此链接:regex101.com。
jex.im 可视化正则表达式:
如果您想要所有可能的名称对,假设您已创建 names.txt 包含:
John
Beatrice
Lucio
我会在 bash 中尝试这个:
$ for n in $(cat names.txt)
> do for m in $(cat names.txt)
> do if [ "$m" != "$n" ]; then
> echo "$n, $m"
> fi
> done
> done
John, Beatrice
John, Lucio
Beatrice, John
Beatrice, Lucio
Lucio, John
Lucio, Beatrice