【问题标题】:How to split a string with multiple patterns in perl?如何在perl中拆分具有多个模式的字符串?
【发布时间】:2012-01-05 08:33:18
【问题描述】:

我想用多个模式分割一个字符串:

例如

my $string= "10:10:10, 12/1/2011";

my @string = split(/firstpattern/secondpattern/thirdpattern/, $string);

foreach(@string) {
    print "$_\n";
}

我想要输出:

10
10
10
12
 1
2011

这样做的正确方法是什么?

【问题讨论】:

    标签: regex string perl split


    【解决方案1】:

    在正则表达式分隔符中使用character class 以匹配一组可能的分隔符。

    my $string= "10:10:10, 12/1/2011";
    my @string = split /[:,\s\/]+/, $string;
    
    foreach(@string) {
        print "$_\n";
    }
    

    说明

    • 斜线对/.../表示要匹配的正则表达式或模式。

    • 这对方括号[...] 表示正则表达式的字符类。

    • 里面是可以匹配的一组可能的字符:冒号:、逗号,、任何类型的空格字符\s和正斜杠\/(反斜杠作为转义字符)。

    • + 需要匹配紧接在它前面的一个或多个字符,在这种情况下是整个字符类。如果没有这个,逗号空间将被视为 2 个单独的分隔符,从而在结果中为您提供一个额外的空字符串。

    【讨论】:

    • 工作得非常好!谢谢。顺便说一句,你介意解释一下这段代码吗? /[:,\s\/]+/
    • 感谢您的额外输入,这简单地解释了一切! :D
    • 我知道这是一个旧线程,但我想知道如何将 []() 添加到分隔符列表中?当我将它添加到那里时,它似乎摆脱了 []()。
    • @KingsInnerSoul,在每个前面添加一个反斜杠,就像我上面的斜杠一样
    【解决方案2】:

    如果数字是你想要的,提取数字:

    my @numbers = $string =~ /\d+/g;
    say for @numbers;
    

    不需要捕获括号,如perlop中所述:

    /g 修饰符指定全局模式匹配——即匹配 在字符串中尽可能多次。它的行为方式取决于 上下文。在列表上下文中,它返回子字符串的列表 由正则表达式中的任何捕获括号匹配。 如果 没有括号,它返回所有匹配的列表 字符串,好像整个模式都有括号。

    【讨论】:

    • 我不知道你强调的行为,谢谢,对高尔夫也有好处!
    • 我不知道我可以使用这种方法。好想法!非常感谢!
    • @quinekxi 不客气。 split 是一个非常好的工具,但我觉得最适合使用统一的分隔符。在这种情况下,通用元素是数字,因此使用它们更容易。
    • @TLP 是的,实际上我使用了这种方法,但我并没有将其标记为答案,只是为了遵守原始问题。无论如何,谢谢你的想法。我很高兴我从你喜欢的陌生人那里得到了这么好的想法。
    • @quinekxi 我的许多答案不是 OP 要求的解决方案,而是我认为他们真正想要的解决方案。你的问题真的是“我如何最好地从这个字符串中提取数字?”所以这就是你得到的答案。 :)
    【解决方案3】:

    错误的工具!

    my $string = "10:10:10, 12/1/2011";
    my @fields = $string =~ /([0-9]+)/g;
    

    【讨论】:

    • 是的,我知道,对不起,我不知道还有其他方法。
    • @quinekxi,不用道歉,你没有做错什么。一个好的答复通常来自考虑更大的图景。问题通常是too specific
    • 感谢您给了我一些思考和考虑另一种解决方案。
    【解决方案4】:

    当您解析的内容显然是日期/时间时,我想知道使用 DateTime::Format::Strptime 将其解析为 DateTime 对象是否更有意义。

    【讨论】:

      【解决方案5】:
      my $string= "10:10:10, 12/1/2011";
      
      my @string = split(m[(?:firstpattern|secondpattern|thirdpattern)+], $string);
      
      my @string = split(m[(?:/| |,|:)+], $string);
      
      print join "\n", @string;
      

      【讨论】:

      • /| |,|: 最好写成[/ ,:]
      • @TLP,是吗? IIRC 交替在内部被编译成一个 trie,一个字符类吗?不是说你错了,真的是个问题。
      • @JoelBerger 我不了解内部结构,但我认为它更具可读性。这是一个基准:perl -wE "use Benchmark qw(cmpthese); $a=qq(10:10:10, 12/1/2011); cmpthese(100000, { Piped => sub { my @r = split (m[(?:/| |,|:)+], $a); }, Class => sub { my @r = split (m[(?:[/ ,:])+], $a); } });"Piped 142450/s -- -27% // Class 194175/s 36% -- 看起来字符类快 36%。
      • 糟糕,没有看到 m 分隔符是括号。奇怪的是它没有抱怨。好吧,使用m##,结果会快 45%。
      • 这个答案更笼统 - 它也可以用于整个单词
      【解决方案6】:

      要回答您最初的问题: 你在找the | operator:

      my $string = "10:10:10, 12/1/2011";
      
      my @string = split(/:|,\s*|\//, $string);
      
      foreach(@string) {
          print "$_\n";
      }
      

      但是,正如其他答案所指出的,您通常可以通过进一步简化或概括来改进这一点。

      【讨论】:

      • 你为什么要链接到页面的 5.10.0 版本,而不是与版本无关的 perldoc.perl.org/perlre.html#Metacharacters
      • @Brad Gilbert:因为那是谷歌给我的第一个,我自己使用的是 5.10,可移植性可能是一个问题,我没有意识到有一个版本无关版本。感谢您提供链接。
      【解决方案7】:

      你可以在非数字上拆分;

      #!/usr/bin/perl
      use strict;
      use warnings;
      use 5.014;
      
      my $string= "10:10:10, 12/1/2011";
      say for split /\D+/, $string;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-27
        • 2010-10-13
        • 1970-01-01
        • 2017-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多