在perl中解析字符串的最佳方法

时间:2018-06-07 16:41:47

标签: perl

为了实现以下任务,我在下面写了类似于perl程序的C(因为我是Perl的新手),但我不确定这是否是最佳实现方式。

有人可以指导吗? 注意:不是完整的程序,而是我可以改进的地方。

提前致谢

输入:

$str = "mail1, local<mail1@mail.local>, mail2@mail.local, <mail3@mail.local>, mail4 local<mail4@mail.local>"

预期产出:

mail1, local<mail1@mail.local>
mail2@mail.local
<mail3@mail.local>
mail4, local<mail4@mail.local>

示例程序

my $str="mail1, \@local<mail1\@mail.local>, mail2\@mail.local, <mail3\@mail.local>, mail4, local<mail4\@mail.local>";
my $count=0, @array, $flag=0, $tempStr="";
for my $c (split (//,$str)) {
    if( ($count eq 0) and ($c eq ' ') ) {
        next;
    }
    if($c) {
        if( ($c eq ',') and ($flag eq 1) ) {
            push @array, $tempStr;
            $count=0;
            $flag1=0;
            $tempStr="";
            next;
        }
        if( ($c eq '>' ) or ( $c eq '@' ) ) {
            $flag=1;
        }
        $tempStr="$tempStr$c";
        $count++;
    }
}
if($count>0) {
    push @array, $tempStr;
}
foreach my $var (@array) {
    print "$var\n";
}

修改

输入:

Input is the output of above code.

预期产出:

"mail1, local"<mail1@mail.local>
"mail4, local"<mail4@mail.local>

示例代码:

$str =~ s/([^@>]+[@>][^,]+),\s*/$1\n/g;
my @addresses = split('\n',$str);
if(scalar @addresses) {
    foreach my $address (@addresses) {
        if (($address =~ /</) and ($address !~ /\"/) and ($address !~ /^</)){
            $address="\"$address";
            $address=~ s/</\"</g;
        }
    }
    $str = join(',',@addresses);
}
print "$str\n";

2 个答案:

答案 0 :(得分:2)

如我所见,你想要替换每一个:

  • 逗号和以下空格
  • 发生在@>之后,

换行。

要进行此类替换,您可以使用,而不是编写解析程序 一个正则表达式。

搜索部分如下:

([^@>]+[@>][^,]+),\s*

详细说明:

  • ( - 第一个捕获组的开始。
    • [^@>]+ - 除@>以外的非空字符序列。
    • [@>] - @>
    • [^,]+ - 除逗号外的非空字符序列。
  • ) - 第一个捕获组结束。
  • ,\s* - 逗号和可选的空格序列。

替换部分应为:

  • $1 - 第一个捕获组。
  • \n - 新行。

所以整个程序比你的程序短得多,可以如下:

my $str='mail1, local<mail1@mail.local>, mail2@mail.local, <mail3@mail.local>, mail4, local<mail4@mail.local>';
print "Before:\n$str\n";
$str =~ s/([^@>]+[@>][^,]+),\s*/$1\n/g;
print "After:\n$str\n";

要替换所有所需的逗号我使用了g选项。

请注意,我将源字符串放在单个引号中,否则为Perl 会抱怨可能是@mail 的无意插入。

修改

您的修改后的要求必须采用不同的方式处理。 “普通”更换不是一种选择,因为现在有一些 片段匹配,片段忽略

所以基本的想法是编写一个带有匹配正则表达式的while循环: (\w+),?\s+(\w+)(<[^>]+>),意思是:

  • (\w+) - 第一个捕获组 - 一系列单词字符(例如mail1)。
  • ,?\s+ - 可选的逗号和一系列空格。
  • (\w+) - 第二个捕获组 - 一系列单词字符(例如local)。
  • (<[^>]+>) - 第三个捕获组 - 除>以外的一系列字符 (实际邮件地址),用尖括号括起来,例如<mail1@mail.local>

在循环的每次执行中,您都可以访问组 在此特定匹配中捕获($1$2,...)。

所以这个循环的内容是打印所有这些捕获的组, 需要额外的字符。

代码(再次比你的短得多)应如下所示:

my $str = 'mail1, local<mail1@mail.local>, mail2@mail.local, <mail3@mail.local>, mail4 local<mail4@mail.local>';
while ($str =~ /(\w+),?\s+(\w+)(<[^>]+>)/g) {
  print "\"$1, $2\"$3\n";
}

答案 1 :(得分:1)

这是一种使用split的方法,在这种情况下还需要一个仔细的正则表达式

use warnings;
use strict;
use feature 'say';

my $string =   # broken into two parts for readabililty
    q(mail1, local<mail1@mail.local>, mail2@mail.local, )
 .  q(<mail3@mail.local>, mail4, local<mail4@mail.local>);

my @addresses = split /@.+?\K,\s*/, $string;

say for @addresses;

split在其分隔符规范中采用完整的正则表达式。在这种情况下,我认为每条记录都是以电子邮件地址后面的逗号分隔的,因此@.+?,

只有在模式开头之前匹配模式时才会想到逗号之前的negative lookbehind。但那些长度不可变,这正是这里的情况。

我们通常可以匹配模式@.+?,然后使用\K form(lookbehind)删除所有先前的匹配,以便它们不会从字符串中取出。因此,当,\s*前面有电子邮件地址@...(未消费的内容)时,上面会在mail1, local<mail1@mail.local> mail2@mail.local <mail3@mail.local> mail4, local<mail4@mail.local> 上拆分。

打印

<...>

编辑询问引用my @addresses = split /@.+?\K,\s*/, $string; #/ stop syntax highlight s/(.+?,\s*.+?)</"$1"</ for @addresses; say for @addresses; 之前的描述。一种简单的方法是,一旦从字符串中解析出地址,就进行另一次传递。例如

$_

循环中的正则表达式是更改数组元素的一种方法。我使用它来提高效率(改变元素),简洁,并作为以下属性的演示。

foreach loop索引变量(或foreach my $elem (@addresses) { $elem =~ s/(.+?,\s*.+?)</"$1"</; } 是当前处理的元素的别名 - 因此更改它会更改该元素。这是在不知不觉中允许的已知错误来源,这是以上述形式显示它的另一个原因。

该陈述也使用statement modifier,它等同于

foreach

这通常被认为是一种更恰当的写作方式,但我发现另一种形式更清楚地强调了元素的改变,而这只是$file_path = $target_dir.$newfilename; $cFile = curl_file_create($file_path); $data = array( "file" => $cFile, ); $target_url = "https://filedrop.gfycat.com"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $target_url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array( "Content-Type: multipart/form-data" )); $response = curl_exec($ch); var_dump($response); // bool(false) here curl_close($ch); 的唯一目的。