如何从段落中找到标题大小写短语
我想从一段文字中提取出句子中的名词短语。
比如说,从这段文字中:
柯南·道尔说,福尔摩斯这个角色的灵感来自于约瑟夫·贝尔博士,柯南·道尔曾在爱丁堡皇家医院做过贝尔的助手。和福尔摩斯一样,贝尔以从微小的观察中得出重大结论而闻名。[1] 迈克尔·哈里森在1971年《埃勒里·奎因的神秘杂志》上发表的一篇文章中提出,这个角色的灵感来自于温德尔·谢尔,一个在1882年一起引起英国媒体广泛关注的谋杀案中的“顾问侦探”。
我们需要提取出像“柯南·道尔”、“福尔摩斯”、“约瑟夫·贝尔博士”、“温德尔·谢尔”等这样的内容。
如果可以的话,我希望能有一个用Python写的解决方案。
2 个回答
2
“re”这种方法很快就会遇到瓶颈。命名实体识别是个非常复杂的话题,远远超出了在StackOverflow上回答的范围。如果你觉得自己有好的解决方案,可以试试用它来识别一些著名的人物,比如Flann O'Brien(也叫Myles na cGopaleen)、苏加诺、哈里·S·杜鲁门、J·埃德加·胡佛、J·K·罗琳、数学家洛必达、乔·迪马吉奥、阿尔杰农·道格拉斯-蒙塔古-斯科特,以及雨果·马克斯·格拉夫·冯·勒亨费尔德。
更新 下面是一个基于“re”的方法,它能找到更多有效的案例。不过我还是觉得这不是个好方法。需要注意的是,我在我的文本示例中把巴伐利亚伯爵的名字进行了简化。如果有人真的想用这种方法,最好使用Unicode,并在某个阶段对空格进行规范化(可以在输入时或输出时处理)。
import re
text1 = """Conan Doyle said that the character of Holmes was inspired by Dr. Joseph Bell, for whom Doyle had worked as a clerk at the Edinburgh Royal Infirmary. Like Holmes, Bell was noted for drawing large conclusions from the smallest observations.[1] Michael Harrison argued in a 1971 article in Ellery Queen's Mystery Magazine that the character was inspired by Wendell Scherer, a "consulting detective" in a murder case that allegedly received a great deal of newspaper attention in England in 1882."""
text2 = """Flann O'Brien a.k.a. Myles na cGopaleen, I Zingari, Sukarno and Suharto, Harry S. Truman, J. Edgar Hoover, J. K. Rowling, the mathematician L'Hopital, Joe di Maggio, Algernon Douglas-Montagu-Scott, and Hugo Max Graf von und zu Lerchenfeld auf Koefering und Schoenberg."""
pattern1 = r"(?:[A-Z][a-z]+[. ]+)+(?:[A-Z][a-z]+)?"
joiners = r"' - de la du von und zu auf van der na di il el bin binte abu etcetera".split()
pattern2 = r"""(?x)
(?:
(?:[ .]|\b%s\b)*
(?:\b[a-z]*[A-Z][a-z]*\b)?
)+
""" % r'\b|\b'.join(joiners)
def get_names(pattern, text):
for m in re.finditer(pattern, text):
s = m.group(0).strip(" .'-")
if s:
yield s
for t in (text1, text2):
print "*** text: ", t[:20], "..."
print "=== Ned B"
for s in re.finditer(pattern1):
print repr(s.group(0))
print "=== John M =="
for name in get_names(pattern2, t):
print repr(name)
输出:
C:\junk\so>\python26\python extract_names.py
*** text: Conan Doyle said tha ...
=== Ned B
'Conan Doyle '
'Holmes '
'Dr. Joseph Bell'
'Doyle '
'Edinburgh Royal Infirmary. Like Holmes'
'Bell '
'Michael Harrison '
'Ellery Queen'
'Mystery Magazine '
'Wendell Scherer'
'England '
=== John M ==
'Conan Doyle'
'Holmes'
'Dr. Joseph Bell'
'Doyle'
'Edinburgh Royal Infirmary. Like Holmes'
'Bell'
'Michael Harrison'
'Ellery Queen'
'Mystery Magazine'
'Wendell Scherer'
'England'
*** text: Flann O'Brien a.k.a. ...
=== Ned B
'Flann '
'Brien '
'Myles '
'Sukarno '
'Harry '
'Edgar Hoover'
'Joe '
'Algernon Douglas'
'Hugo Max Graf '
'Lerchenfeld '
'Koefering '
'Schoenberg.'
=== John M ==
"Flann O'Brien"
'Myles na cGopaleen'
'I Zingari'
'Sukarno'
'Suharto'
'Harry S. Truman'
'J. Edgar Hoover'
'J. K. Rowling'
"L'Hopital"
'Joe di Maggio'
'Algernon Douglas-Montagu-Scott'
'Hugo Max Graf von und zu Lerchenfeld auf Koefering und Schoenberg'
5
这种处理方式可能会非常棘手。下面这段简单的代码几乎做对了:
for s in re.finditer(r"([A-Z][a-z]+[. ]+)+([A-Z][a-z]+)?", text):
print s.group(0)
输出结果是:
Conan Doyle
Holmes
Dr. Joseph Bell
Doyle
Edinburgh Royal Infirmary. Like Holmes
Bell
Michael Harrison
Ellery Queen
Mystery Magazine
Wendell Scherer
England
如果想要包含“Dr. Joseph Bell”,你需要接受字符串中的句号,这样就会出现“爱丁堡皇家医院。像福尔摩斯一样”的情况。
我遇到过类似的问题:分隔句子。