【问题标题】:How to match a string after a character when the line begins with one of two values?当行以两个值之一开头时,如何匹配字符后的字符串?
【发布时间】:2014-05-06 16:02:34
【问题描述】:

我有一个格式如下的文本文件:

# Email File
# List of email addresses
##############################
PRIMARY_EMAIL=abc@123.com
ALTERNATE_EMAIL=123@abc.com
#PRIMARY_EMAIL=def@456.com
#ALTERNATE_EMAIL=456@def.com
PRIMARY_EMAIL=ghi@789.com
ALTERNATE_EMAIL=789@ghi.com

此文件包含员工的主要和备用电子邮件地址。我使用该文件作为我用来向员工发送通知的脚本的输入。如果员工休假,一些电子邮件地址会被注释掉,不需要包含在结果中。

我遇到的问题是,当字符串以“PRIMARY_EMAIL”或“ALTERNATE_EMAIL”开头时,我无法匹配“=”符号后的电子邮件地址。

使用以下代码,我可以获取“PRIMARY_EMAIL”,但它不会获取“ALTERNATE_EMAIL”。如果我使用两个变量获取输入并在正则表达式中特别指出“PRIMARY_EMAIL”或“ALTERNATE_EMAIL”,则下面的代码可以工作,但如果可能的话,我想在一行代码中一次获取所有内容。

while (<$in_file>) {
    $line = $1 if (/^PRIMARY_EMAIL=(.*)|^ALTERNATE_EMAIL=(.*)/);
    chomp;
    if (defined $line) {
        push (@recipient, $line);
    }
}

$to = join("\n", @recipient);
print "\$to = \n", $to, "\n";

输出:

$to =
abc@123.com
ghi@789.com

如您所见,输出/正则表达式不包括“ALTERNATE_EMAIL”之后的值。

输出应该是:

$to = 
abc@123.com
123@abc.com
ghi@789.com
789@ghi.com

我已经到处搜索了一种使用交替来匹配行首的两个不同字符串的方法,同时只在“=”符号之后返回药水,但我发现的每个示例/解释都只涉及字符串开头的单个匹配项。

感谢您的帮助。

【问题讨论】:

    标签: regex perl5.8


    【解决方案1】:

    试试这个:

    my @recipient  = (join("", <DATA>) =~ /^(?:PRIMARY_EMAIL|ALTERNATE_EMAIL)=(.*)/mg);
    my $to = join("\n", @recipient);
    print "\$to = \n", $to, "\n";
    
    __DATA__
    # Email File
    # List of email addresses
    ##############################
    PRIMARY_EMAIL=abc@123.com
    ALTERNATE_EMAIL=123@abc.com
    #PRIMARY_EMAIL=def@456.com
    #ALTERNATE_EMAIL=456@def.com
    PRIMARY_EMAIL=ghi@789.com
    ALTERNATE_EMAIL=789@ghi.com
    

    join("", &lt;DATA&gt;) 这是读取所有行并加入其中。然后使用正则表达式,我将电子邮件直接解析到数组中。

    【讨论】:

    • 我正在使用 Perl 5.8,并且在 Perl 5.10 之前无法使用分支重置。有没有其他方法可以在不使用分支重置的情况下达到相同的结果?
    • @user2063351 你对错误的帖子发表了错误的评论!我没有提到任何关于分支重置的事情!
    • 抱歉...我认为您的正则表达式的 (?: 部分是分支重置。我把冒号误认为是酒吧。
    • ?: 表示从匹配中忽略分组捕获。
    【解决方案2】:

    使用分支重置/^(?|PRIMARY_EMAIL=(.*)|ALTERNATE_EMAIL=(.*))/

          ^
          (?|
               PRIMARY_EMAIL=
     br 1      ( .* )                        # (1)
            |  ALTERNATE_EMAIL=
     br 1      ( .* )                        # (1)
          )
    

    或者,就这个/^(?:PRIMARY_EMAIL|ALTERNATE_EMAIL)=(.*)/

     ^ 
     (?: PRIMARY_EMAIL | ALTERNATE_EMAIL )
     =
     ( .* )                             # (1)
    

    测试用例

     while (<DATA>) {
         if (/^(?:PRIMARY_EMAIL|ALTERNATE_EMAIL)=(.*)/)
         {
            push (@recipient, $1);
         }
     }
    
     $to = join("\n", @recipient);
     print "\$to = \n", $to, "\n";
    
    __DATA__
    # Email File
    # List of email addresses
    ##############################
    PRIMARY_EMAIL=abc@123.com
    ALTERNATE_EMAIL=123@abc.com
    #PRIMARY_EMAIL=def@456.com
    #ALTERNATE_EMAIL=456@def.com
    PRIMARY_EMAIL=ghi@789.com
    ALTERNATE_EMAIL=789@ghi.com
    

    输出>>

     $to =
     abc@123.com
     123@abc.com
     ghi@789.com
     789@ghi.com
    

    这是另一种方式

    $/ = undef;
    print join("\n",(<DATA> =~ /^(?:PRIMARY_EMAIL|ALTERNATE_EMAIL)=(.*)/mg));
    
    __DATA__
    # Email File
    # List of email addresses
    ##############################
    PRIMARY_EMAIL=abc@123.com
    ALTERNATE_EMAIL=123@abc.com
    #PRIMARY_EMAIL=def@456.com
    #ALTERNATE_EMAIL=456@def.com
    PRIMARY_EMAIL=ghi@789.com
    ALTERNATE_EMAIL=789@ghi.com
    

    输出>>

    abc@123.com
    123@abc.com
    ghi@789.com
    789@ghi.com
    

    【讨论】:

    • 这些都不起作用。选项 1 导致以下错误:“正则表达式中无法识别序列 (?|...);在 m/^(?|
    • @user2063351 - 检查branch reset 在 Perl 5.8 中是否可用,可能仅从 5.10 开始。至于选项2,输出是正确的,最后一行输入的是ALTERNATE_EMAIL=789@ghi.com
    • @user2063351 - 我明白了,当您点击不匹配的注释行时,您的代码中的 $line 仍然是从以前定义的。稍微改变你的代码,我添加了一个例子。
    • 原始代码用于补偿错误的正则表达式。当正则表达式改变时,代码需要改变。
    • 分支重置运算符直到 Perl 5.10 才可用,所以它对我不起作用。我在第一条评论中提供的错误消息是指示无法识别分支重置的错误。有没有办法在不重置分支的情况下做同样的事情?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 2021-12-01
    相关资源
    最近更新 更多