Каким питоническим способом разделить строку перед появлением данного набора символов?
Например, я хочу разделить
'TheLongAndWindingRoad'
любое вхождение заглавной буквы (возможно, кроме первой) и получить
['The', 'Long', 'And', 'Winding', 'Road']
.
Изменить: он также должен разделить отдельные вхождения, то есть от того, что 'ABC'
я хотел бы получить
['A', 'B', 'C']
.
'[a-zA-Z][^A-Z]*'
как регулярное выражение.print(re.findall('^[a-z]+|[A-Z][^A-Z]*', 'theLongAndWindingRoad'))
Вот альтернативное решение для регулярного выражения. Проблема может быть переформулирована как «как мне вставить пробел перед каждой прописной буквой перед разделением»:
>>> s = "TheLongAndWindingRoad ABC A123B45" >>> re.sub( r"([A-Z])", r" \1", 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']*"
источник
drops
регулярного выражения также все обычные (просто альфа) слова, которые не начинаются с заглавной буквы. Я сомневаюсь, что это было намерением ОП.Вариант решения @ChristopheD
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
источник
Используйте просмотр вперед:
В Python 3.7 вы можете сделать это:
re.split('(?=[A-Z])', 'theLongAndWindingRoad')
И это дает:
['the', 'Long', 'And', 'Winding', 'Road']
источник
import re filter(None, re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad"))
или
[s for s in re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad") if s]
источник
[s for s in re.compile(r"([A-Z][^A-Z]*)").split( "TheLongAndWindingRoad") if s]
давая['The', 'Long', 'And', 'Winding', 'Road']
filter
аналогично пониманию списка с условием. Вы что-нибудь имеете против?filter(lambdaconditionfunc, ...)
b) в Python 3,filter()
возвращает итератор. Так что они не будут полностью эквивалентными. в) Я думаю,filter()
тоже медленнееЯ думаю, что лучшим ответом может быть разделение строки на слова, не оканчивающиеся на заглавную букву. Это подойдет для случая, когда строка не начинается с заглавной буквы.
re.findall('.[^A-Z]*', 'aboutTheLongAndWindingRoad')
пример:
>>> import re >>> re.findall('.[^A-Z]*', 'aboutTheLongAndWindingRoadABC') ['about', 'The', 'Long', 'And', 'Winding', 'Road', 'A', 'B', 'C']
источник
src = 'TheLongAndWindingRoad' glue = ' ' result = ''.join(glue + x if x.isupper() else x for x in src).strip(glue).split(glue)
источник
Альтернативное решение (если вам не нравятся явные регулярные выражения):
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
источник
Другой без регулярного выражения и возможность сохранить непрерывный верхний регистр, если необходимо
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']
источник
Это возможно с помощью
more_itertools.split_before
инструмента.import more_itertools as mit iterable = "TheLongAndWindingRoad" [ "".join(i) for i in mit.split_before(iterable, pred=lambda s: s.isupper())] # ['The', 'Long', 'And', 'Winding', 'Road']
iterable = "ABC" [ "".join(i) for i in mit.split_before(iterable, pred=lambda s: s.isupper())] # ['A', 'B', 'C']
more_itertools
- это сторонний пакет с более чем 60 полезными инструментами, включая реализации всех исходных рецептов itertools , что исключает их ручную реализацию.источник
Питонический способ может быть:
"".join([(" "+i if i.isupper() else i) for i in 'TheLongAndWindingRoad']).strip().split() ['The', 'Long', 'And', 'Winding', 'Road']
Хорошо работает с Unicode, избегая re / re2.
"".join([(" "+i if i.isupper() else i) for i in 'СуперМаркетыПродажаКлиент']).strip().split() ['Супер', 'Маркеты', 'Продажа', 'Клиент']
источник
Альтернативный способ без использования регулярных выражений или перечисления:
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']
источник
Делюсь тем, что пришло мне в голову, когда я прочитал пост. В отличие от других постов.
strs = 'TheLongAndWindingRoad' # grab index of uppercase letters in strs start_idx = [i for i,j in enumerate(strs) if j.isupper()] # create empty list strs_list = [] # initiate counter cnt = 1 for pos in start_idx: start_pos = pos # use counter to grab next positional element and overlook IndexeError try: end_pos = start_idx[cnt] except IndexError: continue # append to empty list strs_list.append(strs[start_pos:end_pos]) cnt += 1
источник
Замените каждую заглавную букву «L» в данном тексте на пустое место и букву «L». Мы можем сделать это, используя понимание списка, или мы можем определить функцию для этого следующим образом.
s = 'TheLongANDWindingRoad ABC A123B45' ''.join([char if (char.islower() or not char.isalpha()) else ' '+char for char in list(s)]).strip().split() >>> ['The', 'Long', 'A', 'N', 'D', 'Winding', 'Road', 'A', 'B', 'C', 'A123', 'B45']
Если вы решите использовать функцию, вот как это сделать.
def splitAtUpperCase(text): result = "" for char in text: if char.isupper(): result += " " + char else: result += char return result.split()
В случае данного примера:
print(splitAtUpperCase('TheLongAndWindingRoad')) >>>['The', 'Long', 'A', 'N', 'D', 'Winding', 'Road']
Но большую часть времени, когда мы разбиваем предложение на прописные буквы, обычно мы хотим сохранить сокращения, которые обычно представляют собой непрерывный поток прописных букв. Приведенный ниже код поможет.
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 s.split() splitAtUpperCase('TheLongANDWindingRoad') >>> ['The', 'Long', 'AND', 'Winding', 'Road']
Спасибо.
источник