25

我有一个文件,我正在通过 python 脚本更改其格式。我在这个文件中有几个驼峰式字符串,我只想在大写字母之前插入一个空格 - 所以“WordWordWord”变成了“Word Word Word”。

我有限的正则表达式经验让我停滞不前 - 有人能想出一个像样的正则表达式来做到这一点,或者(更好)有没有一种我缺少的更 Pythonic 的方式来做到这一点?

4

10 回答 10

49

你可以试试:

>>> re.sub(r"(\w)([A-Z])", r"\1 \2", "WordWordWord")
'Word Word Word'
于 2008-10-13T21:20:55.540 回答
34

如果有连续的大写字母,则 Gregs 结果可能不是您要查找的结果,因为 \w 消耗了要替换的大写字母前面的字符。

>>> re.sub(r"(\w)([A-Z])", r"\1 \2", "WordWordWWWWWWWord")
'Word Word WW WW WW Word'

回头看可以解决这个问题:

>>> re.sub(r"(?<=\w)([A-Z])", r" \1", "WordWordWWWWWWWord")
'Word Word W W W W W W Word'
于 2008-10-13T21:37:39.550 回答
13

看看我在.NET 上的回答 - 如何将“大写”分隔的字符串拆分为数组?

编辑:也许最好把它包括在这里。

re.sub(r'([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))', r'\1 ', text)

例如:

"SimpleHTTPServer" => ["Simple", "HTTP", "Server"]
于 2008-10-13T21:41:49.087 回答
11

也许更短:

>>> re.sub(r"\B([A-Z])", r" \1", "DoIThinkThisIsABetterAnswer?")
于 2008-10-13T22:17:14.430 回答
7

也许您会对不使用正则表达式的单行实现感兴趣:

''.join(' ' + char if char.isupper() else char.strip() for char in text).strip()
于 2017-08-20T05:02:51.473 回答
5

使用正则表达式,您可以这样做:

re.sub('([A-Z])', r' \1', str)

当然,这只适用于 ASCII 字符,如果你想做 Unicode,那是一个全新的蠕虫罐头 :-)

于 2008-10-13T21:25:17.297 回答
2

如果您有首字母缩写词,您可能不希望它们之间有空格。这个两阶段的正则表达式将保持首字母缩写词的完整性(并且还将标点符号和其他非大写字母视为添加空格的内容):

re_outer = re.compile(r'([^A-Z ])([A-Z])')
re_inner = re.compile(r'(?<!^)([A-Z])([^A-Z])')
re_outer.sub(r'\1 \2', re_inner.sub(r' \1\2', 'DaveIsAFKRightNow!Cool'))

输出将是:'Dave Is AFK Right Now! Cool'

于 2017-10-15T21:14:16.267 回答
0

我同意正则表达式解决方案是最简单的,但我不会说它是最 Pythonic 的。

怎么样:

text = 'WordWordWord'
new_text = ''

for i, letter in enumerate(text):
    if i and letter.isupper():
        new_text += ' '

    new_text += letter
于 2008-10-14T05:51:10.473 回答
0

我认为正则表达式是这里的方法,但只是为了提供一个纯 python 版本,没有(希望)ΤZΩΤZΙΟΥ 指出的任何问题:

def splitCaps(s):
    result = []
    for ch, next in window(s+" ", 2):
        result.append(ch)
        if next.isupper() and not ch.isspace():
            result.append(' ')
    return ''.join(result)

window() 是我用来对项目的滑动窗口进行操作的实用函数,定义为:

import collections, itertools

def window(it, winsize, step=1):
    it=iter(it)  # Ensure we have an iterator
    l=collections.deque(itertools.islice(it, winsize))
    while 1:  # Continue till StopIteration gets raised.
        yield tuple(l)
        for i in range(step):
            l.append(it.next())
            l.popleft()
于 2008-10-14T09:06:22.747 回答
0

对于旧线程 - 想为我的一个要求尝试一个选项。当然这re.sub()是一个很酷的解决方案,但如果没有(或不应该)导入 re 模块,也会得到一个 1 班轮。

st = 'ThisIsTextStringToSplitWithSpace'
print(''.join([' '+ s if s.isupper()  else s for s in st]).lstrip())
于 2021-04-15T18:59:10.647 回答