在出现给定字符集之前将字符串拆分的pythonic方法是什么?
例如,我想'TheLongAndWindingRoad'
在出现大写字母(可能除了第一个大写字母)时进行拆分
,并获取
['The', 'Long', 'And', 'Winding', 'Road']
。
编辑:它也应该拆分单次出现,即从'ABC'
我想获得
['A', 'B', 'C']
。
在出现给定字符集之前将字符串拆分的pythonic方法是什么?
例如,我想'TheLongAndWindingRoad'
在出现大写字母(可能除了第一个大写字母)时进行拆分
,并获取
['The', 'Long', 'And', 'Winding', 'Road']
。
编辑:它也应该拆分单次出现,即从'ABC'
我想获得
['A', 'B', 'C']
。
Answers:
不幸的是,在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']
'[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
所有不以大写字母开头的常规(纯正Alpha)单词。我怀疑那是《任择议定书》的意图。
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, ...)
在Python 3中比b)从左到右更清晰地读取,filter()
返回一个迭代器。因此它们将不会完全等效。c)我预计filter()
也会变慢
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']
使用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']
它还应该拆分单个出现的位置,即从
'ABC'
我想要获得的位置['A', 'B', 'C']
。
iterable = "ABC"
[ "".join(i) for i in mit.split_before(iterable, pred=lambda s: s.isupper())]
# ['A', 'B', 'C']
more_itertools
是带有60多种有用工具的第三方程序包,其中包括所有原始itertools配方的实现,从而避免了它们的手动实现。
使用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
Python方式可能是:
"".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()
['Супер', 'Маркеты', 'Продажа', 'Клиент']
将给定的每个大写字母“ 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']
谢谢。