使用 Template Toolkit 从字符串中提取电子邮件

Extract email from string using Template Tookit

我猜这比较简单,但我找不到答案。

'"John Doe" <email@example.com>' 这样的字符串中 - 如何使用 Template Tookit 从中提取电子邮件部分?

要解析的示例字符串是这样的:

$VAR1 = { 
    'date' => '2021-03-25',
    'time' => '03:58:18',
    'href' => 'https://example.com',
    'from' => 'fezius@evrostroyserov.ru on behalf of Caroline <fezius@evrostroyserov.ru>',
    'bytes' => 13620,
    'pmail' => 'user@example.com',
    'sender' => 'sender@example.com',
    'subject' => 'Some Email Subject'
};

我的代码,基于下面的 帮助,其中 $VAR1dumper.dump(item.from)

的输出
[% text = item.from -%]
[% IF (matches = text.match('(.*?)(\s)?+<(.*?)>')) -%]
<td>[% matches.1 %]</td>
[% ELSE -%]
<td>[% text %]</td>
[% END %]

但是,它仍然不匹配 $VAR1

我不知道 Template Toolkit 可以如何帮助您。使用 Email::Address or Email::Address::XS 解析电子邮件地址。

有一个非常古老(且未维护)的模块,Template::Extract,让您定义一个模板,然后从可能由该模板生成的字符串逆向工作:

use Template::Extract;
use Data::Dumper;

my $obj = Template::Extract->new;
my $template = qq("[% name %]" <[% email %]>);

my $string = '"John Doe" <email@example.com>';

my $extracted = $obj->extract($template, $string);

print Dumper( $extracted );

输出为:

$VAR1 = {
          'email' => 'email@example.com',
          'name' => 'John Doe'
        };

但是,有些模块已经为您完成了这项工作,并且可以处理更多情况

这可以满足您的要求,但它非常脆弱,而且这确实不是您应该在 TT 代码中执行的操作。您应该在模板外部解析数据并将其传递给变量,或者您应该传递一个可以从模板内部调用的解析子例程。

但是,在给了你警告之后,如果你仍然坚持这是你想做的,那么你可以这样做:

test.tt中:

[% text = '"John Doe" <email@example.com>';
   matches = text.match('"(.*?)"\s+<(.*?)>');
   IF matches -%]
Name: [% matches.0 %]
Email: [% matches.1 %]
[% ELSE -%]
No match found
[% END -%]

然后,使用 tpage:

进行测试
$ tpage test.tt
Name: John Doe
Email: email@example.com

但是我怎么强调都不为过,您不应该这样做。

更新:我已经使用这个测试模板来调查你的进一步问题。

[% item = { from => '"John Doe" <email@example.com>' };
   text = item.from -%]
[% IF (matches = text.match('(.*?)(\s)?+<(.*?)>')) -%]
<td>[% matches.1 %]</td>
[% ELSE -%]
<td>[% text %]</td>
[% END %]

然后 运行宁它,我明白了:

$ tpage test2.tt
<td> </td>

这就是我希望看到的比赛。您正在打印 matches.1。这是 matches 数组中的 second 项。而第二个匹配组是(\s)。所以我在名称和左尖括号之间得到 space。

你可能不想在你的 matches 数组中匹配 whitespace,所以我会删除它周围的括号,使正则表达式 (.*?)\s*<(.*?)>(注意\s* 是表示“零个或多个白色 space 字符”)的更简单方式。

您现在可以使用 matches.0 获取姓名并使用 matches.1 获取电子邮件地址。

哦,没有必要将 items.from 复制到 text。您可以在任何标量变量上调用 matches vmethod,因此使用它可能更简单:

[% matches = item.from.match(...) -%]

我有没有提到这是一个非常糟糕的想法? :-)

更新2:

如果您按照我为您提供的方式提供完整的 运行可用代码示例,这一切都会变得容易得多。任何时候我必须编辑一些东西以获得示例 运行ning,我们 运行 冒着我错误地猜测您的代码如何工作的风险。

但是,考虑到这一点,这是我最新的测试模板:

[% item = {
    'date' => '2021-03-25',
    'time' => '03:58:18',
    'href' => 'https://example.com',
    'from' => 'fezius@evrostroyserov.ru on behalf of Caroline <fezius@evrostroyserov.ru>',
    'bytes' => 13620,
    'pmail' => 'user@example.com',
    'sender' => 'sender@example.com',
    'subject' => 'Some Email Subject'
};
   text = item.from -%]
[% IF (matches = text.match('(.*?)(\s)?<(.*?)>')) -%]
<td>[% matches.2 %]</td>
[% ELSE -%]
<td>[% text %]</td>
[% END %]

我已经更改了 item 的定义以包含您的完整示例。我已经离开了我的建议之前的正则表达式。并且(因为我没有更改正则表达式)我将输出更改为打印 matches.2 而不是 matches.1.

事情是这样的:

$ tpage test3.tt
<td>fezius@evrostroyserov.ru</td>

所以它有效。

如果你的代码不起作用,那么你需要确定我的(工作)代码和你的(非工作)代码之间的区别。我很乐意帮助您识别这些差异,但您必须提供您的非工作示例才能让我做到这一点。

更新3:

我再次尝试合并您所说的更改。但同样,我不得不猜测一些东西,因为你没有分享完整的 运行nable 示例。再一次,我的代码按预期工作。

[% USE dumper -%]
[% item = {
    'date' => '2021-03-25',
    'time' => '03:58:18',
    'href' => 'https://example.com',
    'from' => 'fezius@evrostroyserov.ru on behalf of Caroline <fezius@evrostroyserov.ru>',
    'bytes' => 13620,
    'pmail' => 'user@example.com',
    'sender' => 'sender@example.com',
    'subject' => 'Some Email Subject'
};
 -%]
[% matches = item.from.match('(.*?)(\s)?<(.*?)>') -%]
[% dumper.dump(matches) %]

并对其进行测试:

$ tpage test4.tt
$VAR1 = [
          'fezius@evrostroyserov.ru on behalf of Caroline',
          ' ',
          'fezius@evrostroyserov.ru'
        ];

这样就可以了。如果您需要更多帮助,请发送完整的 运行nable 示例。如果你不那样做,我就帮不了你了。