【问题标题】:Perl regex splitting a single linePerl 正则表达式拆分单行
【发布时间】:2019-09-11 15:09:30
【问题描述】:

我在 Perl 中遇到一些正则表达式问题。

我有一条线:#23 = CARTESIAN_POINT ( 'NONE', ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 ) ) ;

而且我想把这条线分成不同的值。

现在我有(#[0-9]+)\s=\s([A-Z]+_[A-Z]+)\s(.*) 这个。这将有这些值作为输出:

$array[0]=#23
$array[1]=CARTESIAN_POINT
$array[2]=( 'NONE',  ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 ) ) ;

我希望这一行:( 'NONE', ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 ) ) ; 拆分为不同的值,例如。

PARAM[0] = 'NONE',
PARAM[1] = ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 )

PARAM[0] = 'NONE',
PARAM[1] = -1.822612853216911200
PARAM[2] = 55.22284222837789300
PARAM[3] = 8.566382866014988600

但我不知道该怎么做。我尝试了不同的东西,但没有一个值得提及。

我希望有人能够帮助我或为我指明正确的方向。提前致谢!

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    这在分成多个(两个)步骤时相当简单。

    先提取带坐标的文字,CARTESIAN_POINT( ... )里面的东西

    my ($coord_text) = $string =~ /= \s+ [A-Z_]+ \s+ \( \s* (.+) \s* \)/x;
    

    /x 允许在其中包含这些空格,以提高可读性。 .+贪婪,它会将所有内容都保存到最后一个 ),包括嵌套的 (...)。 然后从中获取坐标

    my @coords = $coord_text =~ /([A-Z]+|[0-9-.]+)/g;
    

    这里我们允许或者一个词(例如NONE),一个数字(显示格式)。

    总而言之,中间步骤“隐藏”在 do 词法范围内

    use warnings;
    use strict;
    use feature 'say';
    
    my $string = q(#23 = CARTESIAN_POINT ( 'NONE', ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 ) ) ; );
    
    my @coords = do {
        my ($coord_text) = $string =~ /=\s+[A-Z_]+\s+\(\s*(.+)\s*\)/; 
        $coord_text =~ /([A-Z]+|[0-9-.]+)/g;
    };
    
    say for @coords; 
    

    这很容易根据需求/结果的变化进行调整,无论是轻微的还是主要的

    • 若要同时捕获 NONE 周围的引号(如 OP 所示),请将引号添加到单词 [A-Z\x22\x27] 的字符类中。我使用十六进制,以防这是 ​​bash 脚本或类似脚本中的“单行”,因为未指定上下文。在普通脚本中,您可以使用"'

    • 如问题中所述,要获取字符串而不是列表中的数字,请使用

      $coord_text =~ /([A-Z]+|\([^)]+\))/g;
      

      而不是上面do 块中的第二个语句

    我假设您有一个包含单词(如NONE)或坐标(数字)的直接列表的列表,没有任何进一步的嵌套或类似的句法复杂性。

    注意 如果输入可以是多行字符串,则将 /s 修饰符添加到正则表达式。有了它,. 也匹配一个换行符,它的工作原理与上面相同(它在我的测试中)。这应该只在第一个正则表达式中需要,使其成为

    my ($coord_text) = $string =~ /=\s+[A-Z_]+\s+\(\s*(.+)\s*\)/s;
    

    但它也不会伤害另一个。


     使用的字符类 [0-9-.] 也允许垃圾(如 -.-2 等)。如果您需要确认您确实有给定格式的号码,请添加检查。测试数字的最佳方法是 looks_like_number 来自 Scalar::Util

    【讨论】:

    • 感谢详细的解释!我会尽快尝试。
    • @mHvNG 不客气。请注意,我同时进行了一些编辑,特别是我刚刚在末尾添加了一个“Note”,说明如何修改它以使用多行搅拌。
    • 感谢您的帮助。真的很感激!
    【解决方案2】:

    这就是Text::Balanced 的用途。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Text::Balanced qw[extract_bracketed];
    use Data::Dumper;
    
    while (<DATA>) {
      # Extract the bit of your string between the first and last brackets
      my $extracted = extract_bracketed($_, '(', '[^()]*');
      # Then split what's left on strings of brackets, whitespace and commas.
      # But grep the list to remove any zero-length strings that you get.
      my @bits = grep { length } split /[\(\)\s,]+/, $extracted;
      print Dumper \@bits;
    }
    
    __DATA__
    #23 = CARTESIAN_POINT ( 'NONE',  ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 ) ) ;
    

    输出:

    $VAR1 = [
              '\'NONE\'',
              '-1.822612853216911200',
              '55.22284222837789300',
              '8.566382866014988600'
            ];
    

    【讨论】:

      【解决方案3】:

      您需要根据需要多次重复您的模式并提供适当的捕获组:

      #[0-9]+\s*=\s*[A-Z]+_[A-Z]+\s*\(\s*'([A-Z]+)',\s*\(\s*(-?\d+\.\d+),\s*(-?\d+\.\d+),\s*(-?\d+\.\d+)
      

      https://regex101.com/r/GJ6yDi/1/

      【讨论】:

      • 谢谢!我会尽快尝试。
      【解决方案4】:

      如果您不关心嵌套,而只想将所有“值”放入一个数组中,您可以考虑更简单的解决方案,即丢弃所有不需要的(非值)字符:@ 987654321@

      $ cat line
      #23 = CARTESIAN_POINT ( 'NONE',  ( -1.822612853216911200, 55.22284222837789300, 8.566382866014988600 ) ) ;
      
      $ perl -ne '@array = split /[(),;=\s]+/; print join "|", @array; print "\n"' line
      #23|CARTESIAN_POINT|'NONE'|-1.822612853216911200|55.22284222837789300|8.566382866014988600
      
      
      

      【讨论】:

        猜你喜欢
        • 2010-10-15
        • 2012-01-18
        • 1970-01-01
        • 1970-01-01
        • 2019-04-14
        • 2011-06-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多