正则表达式转换模糊的电子邮件地址Perl

时间:2014-11-21 19:34:06

标签: regex perl obfuscation substitution deobfuscation

前言:这是一项学校作业。我不是为了恶意目的而收集电子邮件。

我需要从给定文件中识别,提取和转换电子邮件地址(作为命令行 参数)。对于模糊的电子邮件地址,我需要将电子邮件转换回常规电子邮件地址格式(account-name @ domain-name)。

这些是我需要考虑的混淆技术:

No obfuscation. An email address may be included in a pair of <>. For example, 
1. <anonym@new.efs.edu> or anonym@new.efs.edu.
2. A space MAY be added before or after (or both) the @ sign.
3. The @ sign is written as AT or at, and space is added before and after AT or at. 
4. The . sign in domain name is written as DOT or dot, and space is added before and after DOT 
or dot.

目前我只想说明第一种技术。 "1. <anonym@new.efs.edu> or anonym@new.efs.edu."

这是我到目前为止所做的:

编辑:使用@ikegami的帮助

#!/usr/bin/perl -w

use warnings;
use strict;

my @addrs;
my $re; 
open my $INFILE, '<', $ARGV[0] or die $!;

while( my $line = <$INFILE> ) {
     push @addrs, $line =~ /(\w+\@(?:\w+\.)*\w+)/g;

foreach $re (@addrs) {
     if ($re =~ (/$line/)) {
        print $re;
     }
}
}   


close $INFILE;

不再出错,但无法输出。

示例输入:

Email: <anonym1@efs.new.edu> email: anonym2@efs.new.edu anonym1234@new.edu
Email: anonym3 AT efs.new.edu E-mail: anonym4 at efs.new.edu test at 9:00PM
We will have a test in room 705 @ another time.
Email: anonym5 @ efs dot new dot edu what if we continue
Another test anonym6 at efs dot new dot edu
If you type a dot, it means you have finished typing all contents.
Email:anonym7 AT new DOT efs DOT edu
We can, at 10:00PM, go to library DOT or .
My gmail address is jeff.anonym@gmail DOT com

输出应为:

anonym1234@new.edu
anonym1@efs.new.edu
anonym2@efs.new.edu
anonym3@efs.new.edu
anonym4@efs.new.edu
anonym5@efs.new.edu
anonym6@efs.new.edu
anonym7@efs.new.edu
jeff.anonym@gmail.com

非常感谢任何正确方向的帮助/点!

2 个答案:

答案 0 :(得分:3)

这些问题可能与问题的主题有关:您似乎正在努力解决破坏人们避免收集其电子邮件地址的企图的问题。人们通常会混淆他们的地址,因为他们不希望收获他们的地址。因此,您提出的任何解决方案都可能被用来违反发布混淆地址的人的意图。然而,教授选择一个不受欢迎的话题并不是你的错。

越过那个......

在文本中检测混淆的电子邮件地址是一项不完美的科学,有点像军备竞赛。即使检测有效的电子邮件地址也很棘手。会有误报,也可能是假阴性。即使有一个非常好看的电子邮件地址列表仍然可能有技术上正确但实际上没用的地址。

CPAN模块Email :: Address擅长解析电子邮件地址的文本,但它会出现误报。 Email :: Valid擅长拒绝许多误报。这是一个产生您正在寻找的输出的示例:

use Email::Address;
use Email::Valid;

while( <DATA> ) {
  print "$_\n" for 
    grep { Email::Valid->address( $_->address ) }
      Email::Address->parse( fix_common_obfu($_) );
}

sub fix_common_obfu {
  my $string = shift;
  $string =~ s/\s+dot\s+/./ig;        # Turn ' dot ' into '.'
  $string =~ s/\s+@\s+|\s+at\s+/@/ig; # Turn ' @ ' or ' at ' into '@'.
  return $string;
}

__DATA__
Email: <anonym1@efs.new.edu> email: anonym2@efs.new.edu anonym1234@new.edu
Email: anonym3 AT efs.new.edu E-mail: anonym4 at efs.new.edu test at 9:00PM
We will have a test in room 705 @ another time.
Email: anonym5 @ efs dot new dot edu what if we continue
Another test anonym6 at efs dot new dot edu
If you type a dot, it means you have finished typing all contents.
Email:anonym7 AT new DOT efs DOT edu
We can, at 10:00PM, go to library DOT or .
My gmail address is jeff.anonym@gmail DOT com

这会产生以下输出:

anonym1@efs.new.edu
anonym2@efs.new.edu
anonym1234@new.edu
anonym3@efs.new.edu
anonym4@efs.new.edu
anonym5@efs.new.edu
anonym6@efs.new.edu
anonym7@new.efs.edu
jeff.anonym@gmail.com

<强>更新

这是一个(不太健壮但工作)的解决方案,它避免使用外部CPAN模块,使用正则表达式解决核心问题。

while( <DATA> ) {
  s/\s+@\s*|\s*@\s+/@/g;    # Deal with spaces around @.
  s/\s+at\s+/@/ig;          # Deal with " at "
  s/\s+dot\s+/./ig;         # Deal with " dot "
  while (
    m/(           # Match and capture.
      [^<\s:]+    # One or more characters except <, space, or :.
      @           # Literal '@'
      \S+         # One or more non-space.
      \.          # Require a dot in the domain.
      [^>\s]+     # One or more any character except whitespace or '>'.
    )/gx          # Repeat as many matches as found, allow freeform.
  ) {
    print "$1\n";
  }
}

__DATA__
.... etc etc etc...

我使用/x修饰符来允许正则表达式为自由形式(无效的空格和允许的注释)。这使得它可以被分解成更小的更清晰的块。

答案 1 :(得分:1)

很难解释你做错了什么,因为它有很多,所以我只是提供一些正确的代码。这将扫描其中一种电子邮件:

my @addrs;
while ( my $line = <$INFILE> ) {
   push @addrs, $line =~ /(\w+\@(?:\w+\.)*\w+)/g;
}

或只是

my @addrs;
while (<$INFILE>) {
   push @addrs, /(\w+\@(?:\w+\.)*\w+)/g;
}

提示:由于您接受该文件作为参数读取,因此您也可以使用<>。取代

open my $INFILE, '<', $ARGV[0] or die $!;
while (<$INFILE>) {
    ...
}

while (<>) {
    ...
}

它将从命令行中指定的文件读取,如果没有提供文件,则读取STDIN。所以它更简单,更好!