我正在编写一个Perl程序,它有一个循环文本文件的部分,并提取系统用户的名字和姓氏。但是,在某些用户帐户中,它们可能具有中间名称或具有句点的中间名称。例如,在下面的三个字符串中,我试图仅匹配John(名字)和Smith(姓氏)。我不想存储中间名/ initial(如果有的话):
John Smith
John A. Smith
John Andrew Smith
我试过做类似的事情:
(\w+)(?:\s.*\w)?\s(\w+).*
我读取并捕获第一个单词(名字),然后有一个可选空格,后跟任意字符(中间名),然后是空格,后跟最后一个单词(姓氏)。但这不起作用,我无法提出任何有效的解决方案。
感谢任何帮助!
答案 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 + /(任何空格)。