使用可选中间名匹配全名的正则表达式

时间:2016-10-28 20:43:06

标签: regex perl text

我正在编写一个Perl程序,它有一个循环文本文件的部分,并提取系统用户的名字和姓氏。但是,在某些用户帐户中,它们可能具有中间名称或具有句点的中间名称。例如,在下面的三个字符串中,我试图仅匹配John(名字)和Smith(姓氏)。我不想存储中间名/ initial(如果有的话):

John Smith

John A. Smith

John Andrew Smith

我试过做类似的事情:

(\w+)(?:\s.*\w)?\s(\w+).*

我读取并捕获第一个单词(名字),然后有一个可选空格,后跟任意字符(中间名),然后是空格,后跟最后一个单词(姓氏)。但这不起作用,我无法提出任何有效的解决方案。

感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

您的模式在中间名称的末尾需要一个单词字符(\w),但您的示例 John A. Smith 在中间名称的末尾有一个点。我会改变这样的模式,接受中间名以外的任何空格,这可以解决你的问题。

(\w+)(?:\s[^\s]+)?\s(\w+).*

答案 1 :(得分:0)

由于您需要按空间分割并按位置分析,split使其变得简单。它按给定模式打破字符串并返回获取的列表。只有行上的名称,无论可选的中间部分如何,您都可以获得第一个和最后一个元素,即第一个和最后一个名称。任

my ($first, $last) = (split ' ', $line)[0,-1];

my @name = split ' ', $line;

my $first = shift @name;
my $last  = pop   @name;

如果行上可能有尾随项目,您可以使用特定位置

my ($first, $last) = (@name == 2) ? @name : @name[0,2];

上面用于空间的模式' '有点特殊 - 它适用于任何数量的空白区域,它也会丢弃(可能的)前导空格。当使用空间的一般正则表达式模式时,保留前导空格,并且我们可能最终得到第一个元素的空字符串。请参阅split

如果该行位于$_,例如while (<$fh>),则可以使用split默认值

my ($first, $last) = (split)[0,-1]

请注意,这种方法适用于您列出的名称,但解析名称通常是一个更加圆润的问题。

答案 2 :(得分:-1)

你几乎肯定会碰到许多不起作用的边缘情况。也就是说,如果您确定您的语料库仅包含您提供的格式的名称,则以下内容将起作用:

#!/usr/bin/perl
my @n = (
    "John Smith",
    "John A. Smith",
    "John Andrew Smith",
);
foreach my $full_name (@n) {
    my ($first, $last) = $full_name =~ /^\s*(\S+)\s+(?:\S+\s+)?(\S+)\s*$/;
    print "'$first' '$last'\n";
}

你最好能够捕获全名,但最重要的是,大量遗留系统至少需要自己的姓氏。也许在手动修整东西之前,这会让你更接近。

您还可以更新上述内容以删除任意数量的中间名:

my ($first, $last) = $full_name =~ /^\s*(\S+)\s+(?:\S+\s+)*?(\S+)\s*$/;

关于使用拆分的答案...如果你这样做,请将其更新为拆分/ \ s + /(任何空格)。