【问题标题】:Parsing license file with regex使用正则表达式解析许可证文件
【发布时间】:2018-05-17 14:10:17
【问题描述】:

我想解析一个包含这样内容的许可证文件。

组件="A0000 B0000 G0000"

文件中必须有引号来标记包中组件的开始和结束。我已经在 regex101.com 上测试过组合,但这并不能解决问题

正则表达式("?(?<components>\w+)*\s?"?) 适用于字符串“A0000 B0000 G0000”并返回我需要的组件的各个值:A0000、B0000 等等

但是当我测试 (COMPONENTS|PACKAGES)=("?(?<components>\w+)\s?"?) 时,该块无法返回这些值并且只返回第一个 A0000。

我需要帮助来提取所有这些单独的值。请帮忙。

【问题讨论】:

  • 你的意思是你想要(?:\G(?!^)\s+|(?:COMPONENTS|PACKAGES)=")\K[^\s"]+这样的东西吗?
  • 如果需要引号,为什么要加上'?'他们后面的量词?此外,您的第二个正则表达式查找 \w+ 后跟 \s,但不会重复该模式,因此难怪它只会捕获一个字段。
  • PACKAGES=... 是怎么出现的?是否也有相同类型的线?它们与COMPONENTS 行有什么关系,还是完全独立的?
  • Pranay,当您使用 perl 标签标记问题时,您是指 Perl 5 语言还是您使用的语言中的任何特定选项(如 R)?
  • @WiktorStribiżew 您的解决方案奏效了。如果前面和后面的行包含在正则表达式中,我不明白为什么它不会复制到文件的其他部分。我在标签中包含了perl,因为正则表达式是为 Perl 语言编写的。

标签: regex perl pcre


【解决方案1】:

由于我的解决方案对您有用,因此我发布了答案:

(?:\G(?!^)\s+|(?:COMPONENTS|PACKAGES)=")\K[^\s"]+

模式匹配:

  • (?:\G(?!^)\s+|(?:COMPONENTS|PACKAGES)=") - 两种选择之一:
  • \G(?!^)\s+ - 上一个匹配的结尾(\G 匹配行/字符串的开头或上一个匹配的结尾,所以(?!^)“减去”字符串位置的开头)和 1+ 个空格
  • | - 或
  • (?:COMPONENTS|PACKAGES)= - COMPONENTS=PACKAGES=
  • \K - 匹配重置运算符(丢弃当前匹配的文本)
  • [^\s"]+ - 1 个或多个字符,而不是空格和双引号。

【讨论】:

    【解决方案2】:

    我可能误解了这个问题,但简单的呢

    my %result;
    while (<$fh>) {
        my ($type, $components) = /(\w+)\s*=\s*"([^"]+)/;
        push @{$result{$type}}, split ' ', $components;      # all in one arrayref
        #push @{$result{$type}}, [ split ' ', $components ]; # or as separate ones
    }
    

    这需要多行带有COMPONENTS 和/或PACKAGES(或任何其他主要关键字),并假设它们彼此无关,因此需要单独存储。

    请澄清假设是否错误。

    上面的代码创建了哈希

    ( 组件 => ['A0000', 'B0000', 'G0000', ... ], 包 => [ ... ], )

    其中[ ... ] 是一个数组引用,其中包含该关键字的所有行的组件。

    或者,如果使用代码中被注释掉的那一行而不是上面那一行,

    ( 组件 => [ ['A0000', 'B0000', 'G0000'], [ ... ], ... ], 包 => [ [ ... ], [ ... ], ... ], )

    其中[ ... ] 是带有来自一行的组件的arrayrefs,它们都存储在一个arrayref 中,它是一个键的值。所以这里每行的组件都是单独存储的,而不是像前一种情况一样都在一个 arrayref 中。

    如果在= 之前有任何其他词,它们将存储为自己的键,并带有来自这些行的数据的自己的数组引用。


    更新澄清

    由于引号可能存在​​也可能不存在,因此使用? 使第一个可选

    /(\w+)\s*=\s*"?[^"]+)/;
    

    由于需要匹配其余数据,因此不需要处理尾随的数据

    【讨论】:

    • @ikegami 是的,这似乎更有可能,谢谢。已编辑
    【解决方案3】:

    我将在这里提出一种不同的方法。您的正则表达式模式变得越来越复杂,这不是一个好主意。

    您问题的核心是,要进行重复匹配,您也要匹配前缀文本,而且显然只能匹配一次。

    但是,与其试图让您的正则表达式模式更加复杂,不如以不同的方式解决问题。

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my %conf = do { local $/; <DATA> } =~ m/ (\w+) =" ([^"]+) " /xg; 
    print Dumper \%conf; 
    
    __DATA__
    COMPONENTS="A0000 B0000 G0000"
    PACKAGES="C0000 D0000 E0000"
    

    这将创建一个数据结构。

    $VAR1 = {
              'COMPONENTS' => 'A0000 B0000 G0000',
              'PACKAGES' => 'C0000 D0000 E0000'
            };
    

    如果你想要单独的值。

    $_ = [split] for values %conf;
    print Dumper \%conf; 
    

    这在功能上等同于这个。

    foreach my $key ( keys %conf ) {
    
      #split the value on whitespace.
      my @stuff = split ' ', $conf{$key};
    
      #replace it with your array. 
      $conf{$key} = \@stuff;
    

    }

    哪个产生

    $VAR1 = {
              'PACKAGES' => [
                              'C0000',
                              'D0000',
                              'E0000'
                            ],
              'COMPONENTS' => [
                                'A0000',
                                'B0000',
                                'G0000'
                              ]
            };
    

    所以现在你可以写这个了。

    foreach my $value ( @{$conf{'COMPONENTS'}} ) { 
        print $value,"\n";
    }
    

    【讨论】:

    • 我希望您同意我对您答案的编辑。这次我可能过于挑剔了。如果您不同意我的观点,欢迎您回滚。
    • 基本上我想要两个值,比如一个包中有多少组件,因为文件是这样写的。我想编写一个正则表达式,因为有多组这样的耦合,其中可能有一些可选的捕获组。我用你的一些答案将它们分成不同的正则表达式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多