Разделение имен, которые включают "де", "да" и т.д. В первый, средний, последний и т.д.
Я хочу разделить бразильские имена на части. Однако есть такие имена, как ниже: "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
Есть идея, как это исправить? Есть ли способ использовать один шаблон для "нормального" и "особого" случая?
Ответы
Ответ 1
Будут ли имена всегда записываться каноническим способом, т.е. с каждой частью, заглавной, за исключением 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
требует, чтобы lookbehind были одинаковой ширины. Если в слогах имена не заканчиваются, что вы действительно не можете предположить, вы можете сделать это:
PATTERN = re.compile(r"(?<! da| de| do|dos|das)\s")
Вы можете или не можете иногда спотыкаться о случаях, которые не работают: если первая буква является акцентированным персонажем (или гипотетической гипотезой, содержащейся в нем), она будет соответствовать неверно. Чтобы исправить это, вы не будете использовать внешнюю библиотеку; regex
.
Теперь ваш новый поиск будет выглядеть следующим образом:
regex.findall(r"(?:\p{Ll}+ )?\p{Lu}\w+", "Luiz Ângelo de Urzêda")
\p{Ll}
обозначает любую строчную букву и \p{Lu}
для любой прописной буквы.
Ответ 2
Вы можете использовать это регулярное выражение в findall
с дополнительной группой:
(?:(?:da|de|do|dos|das)\s+)?\S+
Здесь мы делаем (?:da|de|do|dos|das)
и 1+ пробелы после этого необязательного.
Демо-версия RegEx
Демо-версия кода
Пример кода:
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']
Ответ 3
С помощью функции regex.split()
из библиотеки python regex
, которая предлагает дополнительную функциональность:
установки:
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) \s+
не предшествует один из особых случаев da|das|de|do|dos
https://pypi.python.org/pypi/regex/
Ответ 4
Это можно выполнить шаг за шагом после замены 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_")
Ответ 5
Это происходит потому, что вы разделяете строку по своему специальному шаблону. Это действительно разделит строку на две части.
Вы можете попробовать разделить вторую часть дальше, используя "" в качестве разделителя еще раз. Обратите внимание, что это не работает, если есть несколько экземпляров специальных разделителей.
Другим подходом было бы продолжать разделение с использованием "" в качестве разделителя и присоединяться к каждому специальному разделителю со следующим именем. Например:
[Francisco, da, Sousa, Rodrigues] # becomes...
[Francisco, da Sousa, Rodrigues]
Ответ 6
Может быть, вы можете попробовать что-то вроде этого?
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']
Ответ 7
Возможно, это не лучший или элегантный способ, но это сработает. Я также добавил 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']
Ответ 8
Следует отметить, что мы говорим о названиях здесь, а не о названиях.
Эти почти все переводят на что-то вроде "от" или "от", а часть после того, как обычно ссылается на место, и они возникли как титулы для дворянства.
Вы пытаетесь установить не-имя в контекст имени, что делает все сложнее.
Странно пытаться просто удалить все это, как будто этого не существует. Например, если вы возьмете такое имя, как "Стив из Нью-Йорка", и просто попробуйте отказаться от него и сделать Нью-Йорк "фамилией".
Они никогда не были предназначены для фамилий или для того, чтобы вести себя так, как большинство людей будет фамилией. Вещи, которые только что прошли в этом направлении с течением времени, пытаясь сделать круглые колышки в квадратные отверстия.
Вы можете добавить поле заголовка на свою страницу регистрации или что-то еще и направить его для использования людьми с названиями в качестве более элегантного решения.
Ответ 9
Ваше регулярное выражение должно быть изменено на
PATTERN = re.compile(r "\ s (? = [da, de, do, dos, das]) (\ S +\s *\s\s *\S +)" )
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)
Это работает для меня, давая следующие выходы,
['Francisco', 'da Sousa', 'Rodrigues']
['Альберто', 'de Francia', '']