【问题标题】:How do I include new lines in a string in Perl?如何在 Perl 的字符串中包含新行?
【发布时间】:2015-06-05 11:07:25
【问题描述】:

我有一个看起来像这样的字符串

Acanthocolla_cruciata,#8B5F65Acanthocyrta_haeckeli,#8B5F65Acanthometra_fusca,#8B5F65Acanthopeltis_japonica,#FFB5C5

我正在尝试添加新行,以便以列表格式添加。像这样

Acanthocolla_cruciata,#8B5F65
Acanthocyrta_haeckeli,#8B5F65
Acanthometra_fusca,#8B5F65
Acanthopeltis_japonica,#FFB5C5

我有一个 perl 脚本

use strict;
use warnings;

open my $new_tree_fh, '>', 'test_match.txt'
  or die qq{Failed to open "update_color.txt" for output: $!\n};
open my $file,  '<', $ARGV[0]
  or die qq{Failed to open "$ARGV[0]" for input: $!\n};

while ( my $string = <$file> ) {
    my $splitmessage = join ("\n", ($string =~ m/(.+)+\,+\#+\w{6}/gs));

    print $new_tree_fh $splitmessage, "\n";
}

close $file;
close $new_tree_fh;

模式匹配有效,但它不会打印新行,因为我想制作列表。任何人都可以提出任何建议。

【问题讨论】:

  • 我不确定您的模式匹配是否确实有效。您正在使用 (.+) 的贪婪捕获,这会占用您的大部分字符串。

标签: string perl newline


【解决方案1】:

我愿意:

my $str = 'Acanthocolla_cruciata,#8B5F65Acanthocyrta_haeckeli,#8B5F65Acanthometra_fusca,#8B5F65Acanthopeltis_japonica,#FFB5C5';
$str =~ s/(?<=,#\w{6})/\n/g;
say $str;

输出:

Acanthocolla_cruciata,#8B5F65
Acanthocyrta_haeckeli,#8B5F65
Acanthometra_fusca,#8B5F65
Acanthopeltis_japonica,#FFB5C5

【讨论】:

    【解决方案2】:

    好的,我认为您的问题是您的正则表达式不正确匹配。

    (.+)+
    

    例如 - 可能不会像您认为的那样做。这是对一个或多个“任何东西”的贪婪捕获,它会抓住你的整个字符串。

    regex101 上查看。

    试试:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    while ( my $string = <DATA> ) {
        my $splitmessage = join( "\n", ( $string =~ m/(\w+,\#+\w{6})/g ) );
        print $splitmessage, "\n";
    }
    
    __DATA__
    Acanthocolla_cruciata,#8B5F65Acanthocyrta_haeckeli,#8B5F65Acanthometra_fusca,#8B5F65Acanthopeltis_japonica,#FFB5C5
    

    将打印的内容:

    Acanthocolla_cruciata,#8B5F65
    Acanthocyrta_haeckeli,#8B5F65
    Acanthometra_fusca,#8B5F65
    Acanthopeltis_japonica,#FFB5C5
    

    【讨论】:

      【解决方案3】:

      让我们找出现有代码中的问题并从中学习,而不是快速修复解决方案。您的问题出在正则表达式中,因此我们将对其进行剖析和修复。

      ($string =~ m/(.+)+\,+\#+\w{6}/gs)
      
      • 首先,导致该错误的两个重大错误:

        1. 一开始,你在做一个.+,然后匹配,#等等。问题是,.+ 是贪婪的,这意味着它将匹配输入中的 last ,,而不是第一个。因此,当您运行此命令时,几乎整条线(除了最后一株植物的颜色)都与这单个 .+ 匹配。
          有几种不同的方法可以解决此问题,但最简单的方法是限制匹配的内容。不要说.+“匹配任何东西”,而是在开头设置[\w\s]+ - 这意味着匹配“单词字符”(包括字母和数字)或空格字符(因为植物中间有一个空格姓名)。
          ($string =~ m/([\w\s]+)+\,+\#+\w{6}/gs)
          这会改变输出,但仍然不是完全正确的版本,因为:

        2. m/some regex/g 在此处将其匹配项列表作为列表返回,我们希望它返回包括植物名称和颜色在内的整个匹配项。但是,当任何地方的匹配项中有括号时,m/ 只返回与括号匹配的部分(这里是植物名称),而不是整个匹配项。所以,去掉括号,就变成了:
          ($string =~ m/[\w\s]++\,+\#+\w{6}/gs)

      这可行,但相当笨拙且容易出错,因此这里有一些改进建议:

      • 由于您的输入没有换行符,因此末尾的 /s 是不必要的。
        ($string =~ m/[\w\s]++\,+\#+\w{6}/g)
      • ,# 不是 perl 正则表达式中的特殊字符,因此它们前面不需要 \
        ($string =~ m/[\w\s]++,+#+\w{6}/g)
      • + 适用于您只知道角色会出现,但不知道会出现多少次的情况。在这里,由于我们只尝试匹配 one ,one # 字符,因此它们后面的 + 是不必要的。
        ($string =~ m/[\w\s]++,#\w{6}/g)
      • [\w\s] 之后的++ 意味着与+ 完全不同的东西(基本上比平时更贪婪的匹配),所以让我们将其设为单个+
        ($string =~ m/[\w\s]+,#\w{6}/g)
      • (可选)您可以更改最后一个 \w 以仅匹配将出现在颜色代码中的十六进制字符:
        ($string =~ m/[\w\s]+,#[0-9A-F]{6}/g)

      这是一个非常可靠、有效的正则表达式,可以满足您的需求。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-23
        • 1970-01-01
        • 2015-10-01
        • 2011-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多