将包含" de"," da"等的名称拆分为first,middle,last等

时间:2018-01-22 13:54:17

标签: 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 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

知道怎么解决吗?有没有办法只使用一种模式" normal"和#34;特别"情况?

9 个答案:

答案 0 :(得分:9)

名称是否总是以“规范”方式书写,即除了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之前的空间上分开......可悲的是,这是(AFAIK)不可能的,因为re要求lookbehinds具有相同的宽度。如果音节中没有名称​​ end ,您实际上无法假设,可以执行此操作:

PATTERN = re.compile(r"(?<! da| de| do|dos|das)\s")

您可能偶尔也可能不偶然发现不起作用的案件:如果第一个字母是重音字符(或文章,假设包含一个),则它将错误地匹配。要解决这个问题,你不会使用外部库; regex

您的新findall将如下所示:

regex.findall(r"(?:\p{Ll}+ )?\p{Lu}\w+", "Luiz Ângelo de Urzêda")

\p{Ll}引用任何小写字母,\p{Lu}引用任何大写字母。

答案 1 :(得分:2)

您可以在struct Student { var id: Int = 0; var name: String = String(); var course: String = String(); var GPA: Float = 0.0; } let student = [ Student(id: 201520032, name: "Ton Agnis", course: "BSITWMA", GPA: 3.69), Student(id: 201620122, name: "Juan Cruz", course: "BSCSSE", GPA: 2.23), Student(id: 201723214, name: "Pedro Sy", course: "BSITAGD", GPA: 2.87), Student(id: 201418492, name: "Phot xPro", course: "BSCPE", GPA: 3.99) ] func stud(get studs:[Student]){ print("Student No.\t\tID\t\tName\t\t\tCourse\t\tGPA") for i in 0...studs.count - 1{ print("Student \(i+1) \t \(student[i].id)\t\(student[i].name)\t\t\(student[i].course)\t\t\(student[i].GPA)") } } let x = student.sorted{ $0.GPA < $1.GPA } stud(get: student) print(x) 中将此正则表达式与可选组一起使用:

findall

此处我们在此可选项后面生成(?:(?:da|de|do|dos|das)\s+)?\S+ 和1+空格。

RegEx Demo

Code Demo

代码示例:

(?:da|de|do|dos|das)

答案 2 :(得分:2)

使用python&#39; regex库中的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))

输出:

['Francisco', 'da Sousa', 'Rodrigues']
['Emiliano', 'Rodrigo', 'Carrasco']
['Alberto', 'de Francia']
['Bruno', 'Rezende']
  • (?<!das?|de|dos?)\s+ - lookbehind否定断言(?<!...)确保空格\s+之前没有特殊情况之一da|das|de|do|dos

https://pypi.python.org/pypi/regex/

答案 3 :(得分:1)

在使用de_:

替换da和da_之后,可以逐步实现此操作
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']]

编辑:回应评论,如果&#34; Fernanda Rezende&#34;类型名称在那里,然后可以用" 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_")

答案 4 :(得分:0)

这是因为您以特殊模式拆分字符串。这确实会将字符串分成两部分。

您可以尝试进一步分割第二部分,使用&#34; &#34;再次作为分隔符。请注意,如果有多个特殊分隔符实例,这不起作用。

另一种方法是使用&#34; &#34;作为分隔符,并使用以下名称连接每个特殊分隔符。例如:

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

答案 5 :(得分:0)

你可以尝试这样的事吗?

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']

答案 6 :(得分:0)

也许不是最好或最优雅的方式,但这会奏效。我还添加了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']

答案 7 :(得分:0)

应该指出的是,我们在这里讨论的是标题,而不是名称。

这些几乎都转化为“来自”或“来自”之类的东西,而后通常指的是一个地方,它们起源于贵族头衔。

您正在尝试将非名称放入名称上下文中,这会使一切变得困难。

尝试删除所有这些,就像它不存在一样奇怪。就像你拿一个像“来自纽约的史蒂夫”之类的名字一样,只是试图放弃并使纽约成为“姓氏”。

这些从未打算成为姓氏,或者像大多数人的名字一样。随着时间的推移,事情只是朝着那个方向漂移,试图使圆钉适合方孔。

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

答案 8 :(得分:-2)

您的正则表达式应更改为

PATTERN = re.compile(r&#34; \ s(?= [da,de,do,dos,das])(\ S + \ s * \ s \ s * \ S +)&#34;)< / p>

import re

test1 = "Francisco da Sousa Rodrigues" #special split
test3 = "Alberto de Francia" #special split

PATTERN = re.compile(r"\s(?=[da, de, do, dos, das])(\S+\s*\s\s*\S+)")
print re.split(PATTERN, test1)
print re.split(PATTERN, test3)

这适用于我提供以下输出,

[&#39; Francisco&#39;,&#39; da Sousa&#39;,&#39; Rodrigues的&#39;] [&#39; Alberto&#39;,&#39; de Francia&#39;,&#39;&#39;]