Разделить строку на прописные буквы
каков питонический способ разбить строку до появления заданного набора символов?
например, я хочу разделить
'TheLongAndWindingRoad'
при любом появлении прописной буквы (возможно, кроме первой), и получить
['The', 'Long', 'And', 'Winding', 'Road']
.
Edit: он также должен разделять отдельные вхождения, т. е.
от 'ABC'
Я хотел бы получить
['A', 'B', 'C']
.
12 ответов:
к сожалению, это невозможно разделить на матч нулевой ширины в Python. Но вы можете использовать
re.findall
вместо:>>> import re >>> re.findall('[A-Z][^A-Z]*', 'TheLongAndWindingRoad') ['The', 'Long', 'And', 'Winding', 'Road'] >>> re.findall('[A-Z][^A-Z]*', 'ABC') ['A', 'B', 'C']
вот альтернативное решение регулярных выражений. Проблема может быть перефразирована как "как вставить пробел перед каждой прописной буквой, прежде чем делать разделение":
>>> s = "TheLongAndWindingRoad ABC A123B45" >>> re.sub( r"([A-Z])", r" ", s).split() ['The', 'Long', 'And', 'Winding', 'Road', 'A', 'B', 'C', 'A123', 'B45']
это имеет то преимущество, что сохраняются все символы без пробелов, чего нет в большинстве других решений.
>>> import re >>> re.findall('[A-Z][a-z]*', 'TheLongAndWindingRoad') ['The', 'Long', 'And', 'Winding', 'Road'] >>> re.findall('[A-Z][a-z]*', 'SplitAString') ['Split', 'A', 'String'] >>> re.findall('[A-Z][a-z]*', 'ABC') ['A', 'B', 'C']
если вы хотите
"It'sATest"
разделить на["It's", 'A', 'Test']
измените rexeg на"[A-Z][a-z']*"
import re filter(None, re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad"))
или
[s for s in re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad") if s]
вариация на решение @ChristopheD ' s
s = 'TheLongAndWindingRoad' pos = [i for i,e in enumerate(s+'A') if e.isupper()] parts = [s[pos[j]:pos[j+1]] for j in xrange(len(pos)-1)] print parts
альтернативное решение (если вам не нравятся явные регулярные выражения):
s = 'TheLongAndWindingRoad' pos = [i for i,e in enumerate(s) if e.isupper()] parts = [] for j in xrange(len(pos)): try: parts.append(s[pos[j]:pos[j+1]]) except IndexError: parts.append(s[pos[j]:]) print parts
src = 'TheLongAndWindingRoad' glue = ' ' result = ''.join(glue + x if x.isupper() else x for x in src).strip(glue).split(glue)
другой без регулярных выражений и возможность сохранять непрерывный верхний регистр, если требуется
def split_on_uppercase(s, keep_contiguous=False): """ Args: s (str): string keep_contiguous (bool): flag to indicate we want to keep contiguous uppercase chars together Returns: """ string_length = len(s) is_lower_around = (lambda: s[i-1].islower() or string_length > (i + 1) and s[i + 1].islower()) start = 0 parts = [] for i in range(1, string_length): if s[i].isupper() and (not keep_contiguous or is_lower_around()): parts.append(s[start: i]) start = i parts.append(s[start:]) return parts >>> split_on_uppercase('theLongWindingRoad') ['the', 'Long', 'Winding', 'Road'] >>> split_on_uppercase('TheLongWindingRoad') ['The', 'Long', 'Winding', 'Road'] >>> split_on_uppercase('TheLongWINDINGRoadT', True) ['The', 'Long', 'WINDING', 'Road', 'T'] >>> split_on_uppercase('ABC') ['A', 'B', 'C'] >>> split_on_uppercase('ABCD', True) ['ABCD'] >>> split_on_uppercase('') [''] >>> split_on_uppercase('hello world') ['hello world']
альтернативный способ без использования регулярного выражения или перечисления:
word = 'TheLongAndWindingRoad' list = [x for x in word] for char in list: if char != list[0] and char.isupper(): list[list.index(char)] = ' ' + char fin_list = ''.join(list).split(' ')
Я думаю, что это яснее и проще, не связывая слишком много методов или используя длинный список понимания, которые могут быть трудно читать.
альтернативный способ использования
enumerate
иisupper()
код:
strs = 'TheLongAndWindingRoad' ind =0 count =0 new_lst=[] for index, val in enumerate(strs[1:],1): if val.isupper(): new_lst.append(strs[ind:index]) ind=index if ind<len(strs): new_lst.append(strs[ind:]) print new_lst
выход:
['The', 'Long', 'And', 'Winding', 'Road']
это возможно с
more_itertools.split_before
.import more_itertools as mit iterable = "TheLongAndWindingRoad" [ "".join(i) for i in mit.split_before(iterable, lambda s: s.isupper())] # ['The', 'Long', 'And', 'Winding', 'Road']
он также должен разделять отдельные вхождения, т. е. от
'ABC'
Я хотел бы получить['A', 'B', 'C']
.iterable = "ABC" [ "".join(i) for i in mit.split_before(iterable, lambda s: s.isupper())] # ['A', 'B', 'C']
more_itertools
это сторонний пакет с 60 + полезными инструментами, включая реализации для всех оригинальных модуле itertools рецепты, что исключает их ручную реализацию.
замените каждую прописную букву ' L 'в данном с пустым пространством плюс эту букву "L".
def splitAtUpperCase(text): result = "" for char in text: if char.isupper(): result += " " + char else: result += char return result.split()
в случае данного примера:
print(splitAtUpperCase('TheLongAndWindingRoad')) ['The', 'Long', 'And', 'Winding', 'Road']
вы также можете использовать
for
петли сif
заявлениеdef splitAtUpperCase(s): for i in range(len(s)-1)[::-1]: if s[i].isupper() and s[i+1].islower(): s = s[:i]+' '+s[i:] if s[i].isupper() and s[i-1].islower(): s = s[:i]+' '+s[i:] return ' '.join(s.split) print(splitAtUpperCase(TheLongAndWindingRoad) >>>> 'The Long And Winding Road'
спасибо.