【问题标题】:Print email addresses to a file in Perl在 Perl 中将电子邮件地址打印到文件中
【发布时间】:2013-03-30 05:20:48
【问题描述】:

我一直在搜索这个网站和其他网站,以找到完成我需要做的事情的最佳方式,但无济于事。基本上我有一个包含一些姓名和电子邮件地址的文本文件。每个姓名和电子邮件地址都在自己的行中。我需要获取电子邮件地址并将它们打印到另一个文本文件中。到目前为止,我能够打印的只是“未找到电子邮件地址”消息。有什么想法吗?谢谢!!

#!/usr/bin/perl

open(IN, "<contacts.txt") || die("file not found");
#chooses the file to read
open(OUT, ">emailaddresses.txt");
#prints file
$none = "No emails found!";
$line = <IN>;

for ($line)
{
    if ($line =~ /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/g)
    {
        print (OUT $line);
    }
    else
    {
        print (OUT $none);
    }
}

close(IN);
close(OUT);

【问题讨论】:

  • 我们可以看看一些示例输入吗?
  • 您使用的正则表达式假定电子邮件地址只使用大写字母。那是对的吗?此外,尝试用正则表达式匹配电子邮件地址几乎是徒劳的。请参阅Mail::RFC822::Address 了解更多信息。
  • 您只遍历文件的一行...

标签: perl


【解决方案1】:

首先,总是 use strict; use warnings。这有助于编写正确的脚本,并且是调试时非常宝贵的帮助。

另外,使用三参数打开:

open my $fh, "<", $filename or die qq(Can't open "$filename": $!);

我包含了失败的原因 ($!),这也是一个很好的做法。

读取文件(在打开的文件句柄上)的习惯用法是:

while (<$fh>) {
  chomp;
  # The line is in $_;
}

while (defined(my $line = <$fh>)) { chomp $line; ... }

您所做的是将一行读入$line,然后在for 循环中循环该一个项。

(Perl 有一个 context 的概念。像&lt;$fh&gt; 这样的运算符的行为因上下文而异。通常,使用标量变量($ sigil)强制标量上下文,而@,数组的标志,导致列表上下文。这与 PHP 完全不同。)

我会像这样重写你的代码:

use strict; use warnings;
use feature 'say';
my $regex = qr/[A-Z0-9._%+-]+\@[A-Z0-9.-]+\.[A-Z]{2,4}/i; # emails are case insensitive
my $found = 0;

while (<>) { # use special ARGV filehandle, which usually is STDIN
  while (/($regex)/g) {
    $found++;
    say $1;
  }
}
die "No emails found\n" unless $found;

perl script.pl &lt;contacts.txt &gt;emailaddresses.txt 一样调用。 shell 是你的朋友,创建可以通过管道传输的程序是很好的设计。

更新

如果您想要对文件名进行硬编码,我们会将上述脚本与我展示的三参数 open 结合起来:

use strict; use warnings; use feature 'say';
use autodie; # does `... or die "Can't open $file: $!"` for me
my $regex = qr/[A-Z0-9._%+-]+\@[A-Z0-9.-]+\.[A-Z]{2,4}/i;
my $found = 0;

my $contact_file = "contacts.txt";
my $email_file   = "emailaddresses.txt";

open my $contact, "<", $contact_file;
open my $email, ">", $email_file;

while (<$contact>) {    # read from the $contact filehandle
  while (/($regex)/g) { # the /g is optional if there is max one address per line
    $found++;
    say {$email} $1;    # print to the $email file handle. {curlies} are optional.
  }
}
die "No emails found\n" unless $found; # error message goes to STDERR, not to the file

【讨论】:

  • +1: 非常好的“一般提示”,以及提及 &lt;&gt; 变体的荣誉。
  • 谢谢阿蒙,很好的解释。我对您的修订的唯一问题是我的要求规定电子邮件需要写入单独的文本文件。你的重写允许吗?另外,说 $1 是做什么的?我正在读取的文本文件示例如下所示:Jane Doe jdoe@address.com 123456 John Doe john.doe@testing.ca 654321 等
  • @motherconfessor 您之前没有提到文件内容的结构。我的方法将提取电子邮件地址(不包括该行的其余部分)并将其打印出来。 $1 指的是 capture 的内容。您可以使用捕获从正则表达式中提取匹配的文本。您可以通过附加&gt;target 在命令行上指定输出的位置。 &gt; 是大多数 shell 上的重定向运算符。使用 shell 重定向比在脚本中硬编码文件名更灵活。
  • 抱歉,文本文件示例在我上次的评论中没有正确显示。 Jane Doe(新行)jdoe@address.com(新行)123456(新行)John Doe(新行)等等等等。每条信息都在它自己的行上。这会有所作为吗?我也知道使用 shell 比硬编码灵活得多,但是,出于练习的目的,我将如何对其进行硬编码?
  • @motherconfessor 我发布了一个更新,将我的循环与我谈到的三参数开放相结合。
猜你喜欢
  • 2020-11-26
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多