解析西班牙语姓氏

时间:2011-07-15 00:03:21

标签: regex

西班牙语姓氏由三部分组成:

  • 父亲的名字,
  • 可选的母姓名称,
  • 可选配偶的父亲姓名。

这三个部分中的每一个都是一个单词,可以在“De”,“Del”,“De La”,“De Los”或“De Las”之前。这些前缀中的每一个都以大写字母开头,每个部分可能只有一个。配偶的父亲姓名与其他人的名字“de”(没有资本)分开。

如此有效的姓氏将是:

  • 佩雷斯
  • PérezDeLeón
  • LópezdeLópez
  • De LaOcaOrdóñez
  • CastilloRamírezdeDel Valle

我可以使用此正则表达式解析这些名称:

^((?:De |Del |De La |De Los |De Las )?\w+)?( (?:De |Del |De La |De Los |De Las )?\w+)?( de (?:De |Del |De La |De Los |De Las )?\w+)?$

1。)这个丑陋的正则表达式可以简化吗?

2。)当父亲姓名与母姓名称相同时,在他们之间插入“y”字样。所以“López和LópeydeDeLeón”和“PérezyPérez”都是有效的,但“López和Pérez”和“Gómez和deGómez”都没有。我怎么能抓住这个案子?

非常感谢。

2 个答案:

答案 0 :(得分:2)

确切的答案取决于您正在使用的编程语言和/或正则表达式引擎,但对于大多数实现,您应该能够执行以下操作:

(1.)创建一个与名称的单个部分匹配的单独的正则表达式,然后将其包含在最终的正则表达式中,例如,在Perl中:

my $name1 = qr/(?:De |Del |De La |De Los |De Las )?\w+/;
my $name2 = qr/^($name1)( $name1)?( de $name1)?$/;

(我假设您在第一次捕获后不需要?,否则您将匹配空字符串。)$name2然后是匹配的正则表达式。

(2。)严格来说,正确的计算机理论正则表达式无法测试出现在字符串中某一点的任意子字符串是否也出现在另一个点上。但是,大多数正则表达式实现(例如,Perl兼容的“正则表达式”)实际上支持的功能多于真正的正则表达式引擎,因此您可以使用反向引用,如:

my $name2 = qr/^(?:($name1)( $name1)?|($name1) y \3)(de $name1)?$/;

在PCRE中,\3匹配第三个(...)组匹配的完全相同的字符串。如果由于某种原因无法使用反向引用,则唯一的选择是使用正则表达式:

my $name2 = qr/^(?:($name1)( $name1)?|($name1) y ($name1))(de $name1)?$/;

然后,如果匹配后定义$3$4,请测试它们是否相等。 (请注意,上述两个版本都允许使用“LópezLópez”等名称而不使用“y”;如果您想禁止这些名称,则会更难一些。)

答案 1 :(得分:1)

这是我的尝试。它似乎适用于给出的例子:

public class Foo {

    public static void main(String[] args) throws Exception {
        System.out.println(new SpanishName("Pérez"));
        System.out.println(new SpanishName("Pérez De León"));
        System.out.println(new SpanishName("López de López"));
        System.out.println(new SpanishName("De La Oca Ordóñez"));
        System.out.println(new SpanishName("Castillo Ramírez de Del Valle"));
        System.out.println(new SpanishName("López y López de De León"));
        System.out.println(new SpanishName("Pérez y Pérez"));

        // System.out.println(new SpanishName("López y Pérez")); - Throws IAE
        // System.out.println(new SpanishName("Gómez y de Gómez")); - Throws IAE
    }

    public static class SpanishName {

        private final String paternal;
        private final String maternal;
        private final String spousePaternal;

        private static final Pattern NAME_REGEX = Pattern
                .compile("^([\\p{Ll}\\p{Lu}]+?)(?:\\s([\\p{Ll}\\p{Lu}]+?))?(?:\\s([\\p{Ll}\\p{Lu}]+?))?$");

        public SpanishName(String str) {
            str = stripJoinWords(str);
            str = removeYJoin(str);
            final Matcher matcher = NAME_REGEX.matcher(str);
            if (str.contains(" y ") || !matcher.matches()) {
                throw new IllegalArgumentException(String.format("'%s' is not a valid Spanish name", str));
            } else {
                paternal = matcher.group(1);
                maternal = matcher.group(2);
                spousePaternal = matcher.group(3);
            }
        }

        private String removeYJoin(final String str) {
            return str.replaceFirst("^([\\p{Ll}\\p{Lu}]+?) y \\1", "$1 $1");
        }

        private String stripJoinWords(final String str) {
            return str.replaceAll("(?<!\\sy\\s)[Dd]e(?:l| La| Los| Las)?\\s", "");

        }

        @Override
        public String toString() {
            return String.format("paternal = %s, maternal = %s, spousePaternal = %s", paternal, maternal,
                    spousePaternal);
        }
    }
}