【问题标题】:Find runs of capitalized letters查找大写字母的运行
【发布时间】:2015-07-06 21:28:41
【问题描述】:

我有一个包含一些完全大写的单词和一些混合大小写的单词的文件,我想提取完全大写的单词运行(包含在一行中)——也就是说,由\b 分隔并至少包含两个大写字母,没有小写字母。一切都是 7 位的。

所以,例如,如果一行是

The QUICK Brown fox JUMPs OV3R T4E LAZY DoG.

然后我想提取QUICKOV3R T4E LAZY

这是我目前所拥有的:

while (<$fh>) { # file handle
    my @array = $_ =~ /\b[^a-z]*[A-Z][^a-z]*[A-Z][^a-z]*\b/;
    push @bigarray, @array;
}

还有比[^a-z]*[A-Z][^a-z]*[A-Z][^a-z]*更优雅的方式吗?

【问题讨论】:

  • 连续大写,或单词中任意位置的 2+ 个大写。例如CApital 还是 cApiTal?连续很容易。 2+ 任何地方,不是那么多。
  • @MarcB 连续。但也包括其他 \w 字符,但不包括小写字母。
  • "其他 \w 字符,但没有小写字母" - 所以数字和下划线?
  • 示例匹配/非匹配会有所帮助

标签: regex perl


【解决方案1】:

您似乎想要所有单词定义(构造\w)字符。
要查找并允许至少两个大写字母且不允许小写字母,您可能不会
绕开它们必须可选地被大写包围的事实
和或数字或下划线。

也可以只匹配你需要的。

\b[\d_]*[A-Z]+[\d_]*[A-Z]+[\d_]*\b

展开:

 \b 
 [\d_]* 
 [A-Z]+ 
 [\d_]* 
 [A-Z]+ 
 [\d_]* 
 \b 

啊,结果

输入:

The QUICK Brown fox JUMPs OV3R T4E LAZY DoG.  

输出:

 **  Grp 0 -  ( pos 4 , len 5 ) 
QUICK  
-----
 **  Grp 0 -  ( pos 26 , len 4 ) 
OV3R  
-----
 **  Grp 0 -  ( pos 31 , len 3 ) 
T4E  
-----
 **  Grp 0 -  ( pos 35 , len 4 ) 
LAZY  

更新 - 如果您想有选择地匹配由空格分隔的连续部分,
这会奏效。

 # (?&two_caps)(?:\s+(?&two_caps))*(?(DEFINE)(?<two_caps>\b[\d_]*[A-Z]+[\d_]*[A-Z]+[\d_]*\b))

 (?&two_caps) 
 (?:
      \s+ (?&two_caps) 
 )*

 (?(DEFINE)
      (?<two_caps>
           \b 
           [\d_]* 
           [A-Z]+ 
           [\d_]* 
           [A-Z]+ 
           [\d_]* 
           \b 
      )
 )

输出:

 **  Grp 0 -  ( pos 4 , len 5 ) 
QUICK  
 **  Grp 1 -  NULL 
---------
 **  Grp 0 -  ( pos 26 , len 13 ) 
OV3R T4E LAZY  
 **  Grp 1 -  NULL 

【讨论】:

  • +1 为您服务,因为我认为这准确地回答了问题,因为它在您发布此内容前 49 秒出现。在您发布此内容前 49 秒,我更正了问题中的一个错误,此答案不再正确回答问题。
【解决方案2】:

如果你真的想要一个 run 这些匹配,也许使用带有零宽度断言的 split 然后过滤结果:

while (<DATA>) {
    for my $e (split (/(?<=\b)([A-Z0-9_ ]+)(?=\b)/)){
        $e =~ s/^\s+|\s+$//g;
        print "$e\n" unless ($e =~/^$/ or $e =~ /.*[a-z]/);
    }
}

__DATA__
The QUICK Brown fox JUMPs OV3R T4E LAZY DoG.

打印:

QUICK
OV3R T4E LAZY

那么这是如何工作的呢?

split 会将符合您条件的部分与不符合条件的部分分开:

use Data::Dumper;

while (<DATA>) {
    print Dumper split (/(?<=\b)([A-Z0-9_ ]+)(?=\b)/); 
}

打印:

$VAR1 = 'The';
$VAR2 = ' QUICK ';
$VAR3 = 'Brown';
$VAR4 = ' ';
$VAR5 = 'fox';
$VAR6 = ' ';
$VAR7 = 'JUMPs';
$VAR8 = ' OV3R T4E LAZY ';
$VAR9 = 'DoG.';

然后循环遍历该数组,从每个元素中去除空格,并测试小写字符或空行。

这会导致一行为每一行生成你的数组:

grep { $_ =~ /(?=[A-Z]{2,})^[^a-z]+$/ } map {s/^\s+|\s+$//g; $_} split (/(?<=\b)([A-Z0-9_ ]+)(?=\b)/);

【讨论】:

  • 这很有趣,我用 Perl 做了很多工作。使用大量拆分和进一步循环来完成单个正则表达式的功能。我认为这只是我自己对正则表达式的偏执。太多关于正则表达式的讨论是妖怪......无论如何,不​​知道。
  • 我喜欢正则表达式。根本不是妖怪。在这种情况下,这对我来说更有意义......
【解决方案3】:
\b(?=\S*[A-Z]\S*[A-Z])[A-Z0-9]{2,}\b

试试这个。查看演示。

https://regex101.com/r/cK4iV0/24

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-16
    • 2022-09-27
    • 2016-08-18
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    相关资源
    最近更新 更多