如何组合用正则表达式提取的句子中的所有单词?

问题描述 投票:0回答:5

如果可能的话,我想将所有以大写字母开头的单词(不包括行开头的单词)与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*

节点设法将它们单独输入到列中,即:

  • 约翰
  • 比阿特丽斯
  • 卢西奥

现在的目标是创建以大写字母开头的名称之间可能的组合并将它们放入文件中。有什么建议吗?

regex linux awk
5个回答
5
投票

如果输出中的对的顺序无关紧要:

$ 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.


4
投票

这是另一个执行任务的

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

2
投票

当你的结果在数组中时,你可以循环使用

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

1
投票

如果唯一的问题是字符串的第一个单词,我们只需在表达式中添加

.
即可:

.([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 可视化正则表达式:

enter image description here


1
投票

如果您想要所有可能的名称对,假设您已创建 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
© www.soinside.com 2019 - 2024. All rights reserved.