使用Python正则表达式从字符串中提取名称

5

我一直在尝试从字符串中提取姓名,但似乎离成功还很遥远。

以下是代码:

string = "555-1239Moe Szyslak(636) 555-0113Burns, C. Montgomery555 -6542Rev. Timothy Lovejoy555 8904Ned Flanders636-555-3226Simpson, Homer5553642Dr. Julius Hibbert"
regex = re.compile(r'([A-Z][a-z]+(?: [A-Z][a-z]\.)? [A-Z][a-z]+)')
print(regex.findall(string))

这是我得到的输出:
['Moe Szyslak', 'Timothy Lovejoy', 'Ned Flanders', 'Julius Hibbert']
4个回答

10

即使在英语中,提取人名也非常困难。下面的正则表达式可以解决您特定的问题,但可能无法处理其他输入(例如,它无法捕获带破折号的姓名):

re.findall(r"[A-Z][a-z]+,?\s+(?:[A-Z][a-z]*\.?\s*)?[A-Z][a-z]+", string)
#['Moe Szyslak', 'Burns, C. Montgomery', 'Timothy Lovejoy', 
# 'Ned Flanders', 'Simpson, Homer', 'Julius Hibbert']

并带有标题:

TITLE = r"(?:[A-Z][a-z]*\.\s*)?"
NAME1 = r"[A-Z][a-z]+,?\s+"
MIDDLE_I = r"(?:[A-Z][a-z]*\.?\s*)?"
NAME2 = r"[A-Z][a-z]+"

re.findall(TITLE + NAME1 + MIDDLE_I + NAME2, string)
#['Moe Szyslak', 'Burns, C. Montgomery', 'Rev. Timothy Lovejoy', 
# 'Ned Flanders', 'Simpson, Homer', 'Dr. Julius Hibbert']

作为附注,只有在计划重复使用正则表达式时才需要进行编译。

非常感谢,先生。但是我如何获取头衔?博士、牧师等。 - MQaiser
你在问题中从未提到标题。请查看更新的答案。 - DYZ

6

花式正则表达式需要时间来构建,且难以维护。在这种情况下,我倾向于保持简单:

re.findall(r"[^()0-9-]+", string)

输出结果:

['Moe Szyslak', ' ', 'Burns, C. Montgomery', ' ', 'Rev. Timothy Lovejoy', ' ', 'Ned Flanders', 'Simpson, Homer', 'Dr. Julius Hibbert']

如果空格是一个问题,可以使用过滤器:list(filter(str.strip,list))


但是有些名称确实带有破折号,请保留它们。 - DYZ

1
这里有一种方法,使用零宽度回顾来隔离每个名称:
string = "555-1239Moe Szyslak(636) 555-0113Burns, C. Montgomery555 -6542Rev. Timothy Lovejoy555 8904Ned Flanders636-555-3226Simpson, Homer5553642Dr. Julius Hibbert"
result = re.findall(r'(?:(?<=^)|(?<=[^A-Za-z.,]))[A-Za-z.,]+(?: [A-Za-z.,]+)*(?:(?=[^A-Za-z.,])|(?=$))', string)

print(result)

['Moe Szyslak', 'Burns, C. Montgomery', 'Rev. Timothy Lovejoy', 'Ned Flanders',
 'Simpson, Homer', 'Dr. Julius Hibbert']

实际匹配的模式是这样的:
[A-Za-z.,]+(?: [A-Za-z.,]+)*

这段文字意思是匹配任何大写或小写字母、点号或句号,后跟一个空格和一个或多个相同字符,零次或多次。
此外,我们在此模式的左侧和右侧使用以下环视:
(?:(?<=^)|(?<=[^A-Za-z.,]))
Lookbehind and assert either the start of the string, or a non matching character
(?:(?=[^A-Za-z.,])|(?=$))
Lookahead and asser either the end of the string or a non matching character

-1

我使用spacy在短时间内提取实例名称的实体。使用spacy,您可以依赖预训练的语言模型,这些模型具有关于常见名称和头衔的大量知识。

  1. 步骤:设置spacy并下载预训练的英语语言模型 import spacy
    import en_core_web_sm nlp = en_core_web_sm.load()

  2. 步骤:创建spacy文档 doc = nlp('555-1239Moe Szyslak(636) 555-0113Burns, C. Montgomery555 -6542Rev. Timothy Lovejoy555 8904Ned Flanders636-555-3226Simpson, Homer5553642Dr. Julius Hibbert')

  3. 步骤:获取标记为人的文档中所有令牌的标签 print([(X.text, X.label_) for X in doc.ents if X.label_ == PERSON])


(555,555,C. Montgomery555,Timothy Lovejoy555,Flanders636,555,Julius Hibbert)- 看起来不对。 - DYZ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接