如何在 Perl 中的字符串中包含新行?

How do I include new lines in a string in Perl?

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

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;

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

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

(.+)+

例如 - 可能并不像您认为的那样。这是对 "anything" 中 1 个或多个的贪婪捕获,这将捕获您的整个字符串。

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

我愿意:

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

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

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

    1. 一开始,你在做一个.+,然后匹配,#等等。问题是,.+ 是贪心的,这意味着它将匹配输入中的 last ,,而不是第一个。所以当你 运行 这个时,几乎整行(除了最后一种植物的颜色)都与这个 .+.
      相匹配 有几种不同的方法可以解决此问题,但最简单的方法是限制要匹配的内容。不要说 .+ "match anything",而是在开头写成 [\w\s]+ - 这意味着匹配 "word characters"(包括字母和数字)或 space 个字符(因为植物名中间有个space。
      ($string =~ m/([\w\s]+)+\,+\#+\w{6}/gs)
      这改变了输出,但仍然不是完全正确的版本,因为:

    2. m/some regex/g returns 其匹配列表作为列表,我们想要的是 return 整个匹配包括植物名称和颜色。但是,当匹配中任何地方有括号时,m/ return只是括号匹配的部分(这里是植物名),而不是整个匹配。所以,去掉括号,它变成:
      ($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)

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