Python 拆分名称,包括;",&引用;“da”;,分为第一、中间、最后等

Python 拆分名称,包括;",&引用;“da”;,分为第一、中间、最后等,python,regex,python-3.x,Python,Regex,Python 3.x,我想把巴西名字分成几个部分。但是,也有一些名称,如下面的“de”,“da”(以及其他名称),它们不是单独的部分,并且总是与下面的单词一起出现。所以正常分割不起作用 test1 = "Francisco da Sousa Rodrigues" #special split test2 = "Emiliano Rodrigo Carrasco" #normal split test3 = "Alberto de Francia" #special split test4 = "Bruno Rezen

我想把巴西名字分成几个部分。但是,也有一些名称,如下面的
“de”
“da”
(以及其他名称),它们不是单独的部分,并且总是与下面的单词一起出现。所以正常分割不起作用

test1 = "Francisco da Sousa Rodrigues" #special split
test2 = "Emiliano Rodrigo Carrasco" #normal split
test3 = "Alberto de Francia" #special split
test4 = "Bruno Rezende" #normal split
我的预期产出是:

[Francisco, da Sousa, Rodrigues] #1
[Emiliano, Rodrigo, Carrasco] #2
[Alberto, de Francia] #3
[Bruno, Rezende] #4
对于特殊情况,我尝试了以下模式:

PATTERN = re.compile(r"\s(?=[da, de, do, dos, das])")
re.split(PATTERN, test1) (...)
但结果并不是我所期望的:

['Francisco', 'da Sousa Rodrigues'] #1
['Alberto', 'de Francia'] #3

知道怎么修吗?有没有一种方法可以在“普通”和“特殊”情况下都使用一种模式?

这种情况的发生是因为您在特殊模式下拆分字符串。这确实会把绳子分成两部分

您可以尝试进一步拆分第二部分,再次使用“”作为分隔符。请注意,如果存在多个特殊分隔符实例,则这不起作用

另一种方法是使用“”作为分隔符进行拆分,并使用以下名称连接每个特殊分隔符。例如:

[Francisco, da, Sousa, Rodrigues] # becomes...
[Francisco, da Sousa, Rodrigues]

名称是否总是以“规范”的方式书写,即除da、de、do等外,每个部分都大写

在这种情况下,您可以使用以下事实:

>>> import re
>>> for t in (test1, test2, test3, test4):
... print(re.findall(r"(?:[a-z]+ )?[A-Z]\w+", t, re.UNICODE))
['Francisco', 'da Sousa', 'Rodrigues']
['Emiliano', 'Rodrigo', 'Carrasco']
['Alberto', 'de Francia']
['Bruno', 'Rezende']
>>>
做你想做的事情的“正确”方式(除了完全不做之外)是消极的回头看:当在一个没有da、de、do……的空间上时,分开。不幸的是,这是不可能的,因为
re
要求lookbehind的宽度相等。如果没有名字以音节结尾,你真的无法假设,你可以这样做:


\p{Ll}
指的是任何小写字母,
\p{Lu}
指的是任何大写字母。

您可以在
findall
中使用此正则表达式,并使用可选组:

(?:(?:da|de|do|dos|das)\s+)?\S+
这里我们将
(?:da | de | do | dos | das)
和1+空格设置为可选

代码示例:

test1 = "Francisco da Sousa Rodrigues" #special split
test2 = "Emiliano Rodrigo Carrasco" #normal split
test3 = "Alberto de Francia" #special split
test4 = "Bruno Rezende" #normal split

PATTERN = re.compile(r'(?:(?:da|de|do|dos|das)\s+)?\S+')

>>> print re.findall(PATTERN, test1)
['Francisco', 'da Sousa', 'Rodrigues']

>>> print re.findall(PATTERN, test2)
['Emiliano', 'Rodrigo', 'Carrasco']

>>> print re.findall(PATTERN, test3)
['Alberto', 'de Francia']

>>> print re.findall(PATTERN, test4)
['Bruno', 'Rezende']
使用python库中的
regex.split()

安装:

pip install regex
用法:

import regex as re

test_names = ["Francisco da Sousa Rodrigues", "Emiliano Rodrigo Carrasco",
              "Alberto de Francia", "Bruno Rezende"]

for n in test_names:
    print(re.split(r'(?<!das?|de|dos?)\s+', n))

  • (?-lookbehind否定断言
    (?确保空格
    \s+
    前面没有特殊情况
    da | das | de | do | dos

您的正则表达式应更改为

模式=重新编译(r“\s(?=[da,de,do,dos,das])(\s+\s*\s\s*\s+)

这对我来说很有效,提供了以下输出

['Francisco'、'da Sousa'、'Rodrigues']
[Alberto',“de Francia',”]

在将da替换为da,将de替换为de后,可以逐步实现这一点:

lst = ["Francisco da Sousa Rodrigues" , 
    "Emiliano Rodrigo Carrasco" , 
    "Alberto de Francia" , 
    "Bruno Rezende" ] 

# replace da with da_ and de with de_
lst = list(map(lambda x: x.replace(" da ", " da_"), lst) ) 
lst = list(map(lambda x: x.replace(" de ", " de_"), lst) ) 
# now split names and then convert back _ to space: 
lst = [ [k.replace("_", " ")
        for k in l.split()]
      for l in lst ]
print(lst)
输出:

[['Francisco', 'da Sousa', 'Rodrigues'], 
 ['Emiliano', 'Rodrigo', 'Carrasco'], 
 ['Alberto', 'de Francia'], 
 ['Bruno', 'Rezende']]
编辑:作为对评论的回应,如果存在“Fernanda Rezende”类型名称,则可以用
“da”
替换
“da”
(上面的代码从先前的
“da”
更改为
“da”

还可以定义一个简单的函数来更改列表的所有字符串,然后使用它:

def strlist_replace(slist, oristr, newstr):
    return [ s.replace(oristr, newstr)
             for s in slist ]

lst = strlist_replace(lst, " da ", " da_")
lst = strlist_replace(lst, " de ", " de_")

也许你可以试试这样的东西

b_o_g=['da', 'de', 'do', 'dos', 'das']
test1 = "Francisco da Sousa Rodrigues"
test3= "Alberto de Francia"




def _custom_split (bag_of_words,string_t):
    s_o_s = string_t.split()
    for _,__ in enumerate(s_o_s):
        if __ in bag_of_words:
            try:
                s_o_s[_]="{} {}".format(s_o_s[_],s_o_s[_+1])
                del s_o_s [ _ + 1]

            except IndexError:
                pass
    return s_o_s

print(_custom_split(b_o_g,test1))
print(_custom_split(b_o_g,test3))
输出:

['Francisco', 'da Sousa', 'Rodrigues']
['Alberto', 'de Francia']

也许不是最好或优雅的方式,但这会起作用。我还添加了test5只是为了确定

special_chars = ['da', 'de', 'do', 'dos', 'das']

test1 = "Francisco da Sousa Rodrigues" #special split
test2 = "Emiliano Rodrigo Carrasco" #normal split
test3 = "Alberto de Francia" #special split
test4 = "Bruno Rezende" #normal split
test5 = 'Francisco da Sousa de Rodrigues'

def cut(test):
    t1 = test.split()
    for i in range(len(t1)):
        if t1[i] in special_chars:
            t1[i+1] = t1[i] + ' ' + t1[i+1]
    for i in t1:
        if i in special_chars:
            t1.remove(i)
    print(t1)

cut(test1)
cut(test2)
cut(test3)
cut(test4)
cut(test5)
结果是:

['Francisco', 'da Sousa', 'Rodrigues']
['Emiliano', 'Rodrigo', 'Carrasco']
['Alberto', 'de Francia']
['Bruno', 'Rezende']
['Francisco', 'da Sousa', 'de Rodrigues']

应该指出的是,我们在这里谈论的是头衔,而不是名字

这些几乎都翻译成“from”或“of”,后面的部分通常指一个地方,它们起源于贵族头衔

您正试图将一个非名称放入名称上下文中,这使得一切都很困难

把这一切都去掉,好像它不存在,这是很奇怪的。比如你取了一个名字,比如“史蒂夫从纽约来”,然后把这个名字去掉,把纽约变成“姓氏”

这些名字从来都不是为了成为姓氏,也不是像大多数人认为的那样,只是随着时间的推移,事情朝着这个方向发展,试图让圆形的钉子塞进方形的孔中


您可以在注册页面或其他页面中添加标题字段,并将其作为更优雅的解决方案直接用于有标题的人。

“…每个部分都大写,除了…”这里有很多好的答案,但我将使用这个。刚刚与团队确认,所有的“特殊”单词将用小写字母书写。Thanks@L3viathan当单词以一些奇怪的字母开头时,如test5=“Luiz-ngelo de Urzêda”,我对这种方法有问题。它完全跳过了第二个单词。@pawelty我预见到了这个问题,并在一小时前编辑了我的答案;你需要
regex
模块。如果你只关心典型的巴西名字,这很好。如果你有一个名为“Kitty St John O'Connor”的巴西公民(她实际上是爱尔兰人,也是孩子的母亲),效果就不太好了@pawelty Ok OP.为什么要拆分名称?我想计算每个部分在Firstname中出现的频率和在姓氏中出现的频率。然后,根据我们的编辑指南,我将它们分为first/middle/Nastname字段。在100%的情况下,这可能并不完美,但我们对此没有问题。@pawelty我没有更好的解决方案,因为regex会这样做,但为什么不将所有内容拆分,然后在结果列表上迭代,搜索“de”并将其与列表中的下一项作为字符串连接起来?从概念上讲似乎更容易,但我猜您在这方面有一个性能原因,对吗?不要误解,不要质疑您的方法,恰恰相反-想了解其他人在做什么我得到这个错误:错误:向后看需要固定宽度pattern@pawelty,我道歉s是带有扩展的
regex
库的解决方案,它提供了额外的功能。请参阅我的update@ktsenuri
[da,de,do,dos,das]
并没有达到您期望的效果。它相当于
[adeos,]
,即,匹配包括逗号或空格在内的任何字符。@cpburnz感谢您的解答,因此它应该改为PATTERN=re。compile(r“\s(?=[da | de | do | dos | das])(\s+\s*\s*\s*\s+)@ktsenuri否,
[…]仅用于matc
b_o_g=['da', 'de', 'do', 'dos', 'das']
test1 = "Francisco da Sousa Rodrigues"
test3= "Alberto de Francia"




def _custom_split (bag_of_words,string_t):
    s_o_s = string_t.split()
    for _,__ in enumerate(s_o_s):
        if __ in bag_of_words:
            try:
                s_o_s[_]="{} {}".format(s_o_s[_],s_o_s[_+1])
                del s_o_s [ _ + 1]

            except IndexError:
                pass
    return s_o_s

print(_custom_split(b_o_g,test1))
print(_custom_split(b_o_g,test3))
['Francisco', 'da Sousa', 'Rodrigues']
['Alberto', 'de Francia']
special_chars = ['da', 'de', 'do', 'dos', 'das']

test1 = "Francisco da Sousa Rodrigues" #special split
test2 = "Emiliano Rodrigo Carrasco" #normal split
test3 = "Alberto de Francia" #special split
test4 = "Bruno Rezende" #normal split
test5 = 'Francisco da Sousa de Rodrigues'

def cut(test):
    t1 = test.split()
    for i in range(len(t1)):
        if t1[i] in special_chars:
            t1[i+1] = t1[i] + ' ' + t1[i+1]
    for i in t1:
        if i in special_chars:
            t1.remove(i)
    print(t1)

cut(test1)
cut(test2)
cut(test3)
cut(test4)
cut(test5)
['Francisco', 'da Sousa', 'Rodrigues']
['Emiliano', 'Rodrigo', 'Carrasco']
['Alberto', 'de Francia']
['Bruno', 'Rezende']
['Francisco', 'da Sousa', 'de Rodrigues']