【问题标题】:Is there a way to match all adjacent words in a sentence?有没有办法匹配句子中所有相邻的单词?
【发布时间】:2022-08-15 11:42:04
【问题描述】:
my $line = \"The quick brown fox jumps over the lazy dog.\";

while ($line){
    $line =~ s/[\"\",]//ig; #[] means to get rid of 
    #print $line
    $line = lc($line); #lc is lowercase
        while ($line=~m/\\b(\\w+\\s\\w+)\\b/ig){ #[^ ] means any character except spaces and newline #($line=~m/\\b(\\s\\w+\\s\\w+)\\b/ig)
        my $word =$1;
        print \"$word\\n\";
        $wordcount{$word} += 1;
         
    }
last;

}
close(INPUT);
close(OUTPUT);

期望的输出将是:快速,快速的棕色狐狸,棕色狐狸,狐狸跳跃......但是,对于上面的代码,我只得到快速,棕色狐狸,跳跃......

  • [^ ] 表示“任何不是空格的字符”。它不包括换行符。为什么会呢? [^ \\n] 将匹配“任何不是空格或换行符的字符”。
  • @GüntherBayler \\S 将包括标点符号,就是一个例子。 OP 想要计算单词,并不是所有的非空白字符都是单词字符。例如,fox?fox 不同。
  • @7akeoverforce 顺便说一句:那里不需要\\b(单词边界锚点)——前面的\\w+(单词字符串)在第一个“非单词”字符处停止精确匹配,即如何定义 \"word boundary\"(\\w\\W(非单词字符)之间的位置)

标签: regex perl


【解决方案1】:

要捕获两个但不消耗第二个,以便对重叠,lookahead 很有用

use warnings;
use strict;
use feature 'say';

my $string = shift // 'The quick brown fox jumps over the lazy dog.';
 
while ( $string =~ /(\w+)\s+(?=(\w+))/g ) { 
   say "$1 $2";
}

根据需要打印。这允许单词之间有任意数量的空格。


一个解释。

在使用(\w+) 捕获一个单词后,前瞻(?=...) 只是断言(“向前看”)另一个单词跟随但不消耗它也不会超过它(当我们用(额外)parens 捕获它时,所以我们获取在$1$2 中捕获的两个单词)。正则表达式引擎停留在最后一个匹配后的字符(第一个单词和后面的空格)。

因此,在下一次迭代中,它匹配下一个单词——前瞻最后找到的单词——并通过前瞻发现下一个单词,再次捕获两者。等等。


如果您确实只想允许一个whitespace,请放弃+ 并仅使用\s。如果您只需要文字空间——没有制表符等,请参阅链接以了解 \s 匹配的内容——然后使用 \s+ 代替 (文字空间,空间) 或[ ],为清楚起见,“字符类”(括号)内的文字空间。

【讨论】:

    【解决方案2】:

    您可以使用

    (\w+)\s(?=(\w+\b))
    

    正则表达式解释

    • (抓拍组
      • \w+匹配一个单词
    • )关闭群
    • \s 匹配一个空格
    • (?= Lookahead assertion - 断言以下正则表达式匹配
      • (抓包组
        • \w+\b匹配一个词
      • )关闭群
    • ) 关闭前瞻

    见正则表达式demo

    Perl 示例

    my $line = "The quick brown fox jumps over the lazy dog.";
    
    while ($line =~ /(\w+)\s(?=(\w+\b))/g) {
        print("$1 $2\n");
    }
    

    输出

    The quick
    quick brown
    brown fox
    fox jumps
    jumps over
    over the
    the lazy
    lazy dog
    

    【讨论】:

      【解决方案3】:

      如果将字符串拆分为单词数组,则根本不需要对正则表达式做任何花哨的事情:

      #!/usr/bin/env perl                                                                                                                                                                                                                              
      use strict;
      use warnings;
      use feature qw/say/;
      
      my $line = "The quick brown fox jumps over the lazy dog.";
      $line =~ s/[^\w\s]//g; # Remove non-word, non-whitespace characters                                                                                                                                                                              
      my @words = split ' ', $line;
      for my $i (0 .. $#words - 1) {
          say "$words[$i] $words[$i + 1]";
      }
      

      【讨论】:

      • 很好 - 然后只是用非单词分割它? my @words = split /\W+/, $line;
      猜你喜欢
      • 1970-01-01
      • 2020-06-12
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 2014-10-02
      相关资源
      最近更新 更多