在Python中,在大写字母前插入空格的一种Pythonic方法

33
我有一个文件,正在通过Python脚本修改其格式。在这个文件中,我有几个驼峰式字符串,我只想在大写字母前插入一个空格,例如"WordWordWord"变为"Word Word Word"。
我的正则表达式经验有限,无法解决这个问题 - 请问有没有人能够想到一个合适的正则表达式来实现这个目标?或者(更好的情况下)是否有我所错过的更Pythonic的解决方法?
10个回答

61

您可以尝试:

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

4
re.sub(r"(\w)([A-Z])", r"\1 \2", "SorryIThinkYouMissedASpot") - tzot
作为一个小的改进,应该使用[[:upper:]]而不是[A-Z]。 - Tomalak
6
@Tomalak,Python不支持[[:upper:]]。它是一个POSIX字符类表达式(POSIX bracket expression)的一部分。 - Markus Jarderot
3
对于像我这样的人,请确保你 - 导入 re。 - blobbymatt

38

如果有连续的大写字母,那么格雷格的结果可能不是你要找的,因为 \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'

丹的答案更好,更简单 :) - hayalci
1
@hayalci: re.sub('([A-Z])', r' \1', 'Really?')@hayalci:re.sub('([A-Z])', r' \1', '真的吗?') - tzot

15

1
你的回答可能是 Electrons_Ahoy 真正想要的;然而,根据他们问题的措辞,似乎不是这样。 - tzot
但感谢您分享这个答案,这是一个很棒的回答! - Fight Fire With Fire
太棒了!正是我在寻找的东西。 - Scott Siddall

14
也许你对不使用正则表达式的一行代码实现感兴趣:
''.join(' ' + char if char.isupper() else char.strip() for char in text).strip()

1
优雅的回答... 非常感谢 - karthikeyan

14

可能更短:

>>> re.sub(r"\B([A-Z])", r" \1", "DoIThinkThisIsABetterAnswer?")

2
对于任何想知道的人,\B表示“非单词边界”。因此,在已经有空格的地方不会插入空格。 - ArtOfWarfare

5
使用正则表达式,您可以做到这一点:
re.sub('([A-Z])', r' \1', str)

当然,这只适用于ASCII字符,如果你想处理Unicode字符,那就是一个全新的挑战了 :-)

2
re.sub('([A-Z])', r' \1', "Do we want a space before the D's of this phrase?") - tzot
啊,是的,说得好。看起来你和Leonhard的解决方案都正确地处理了这个问题。 - Dan Lenski

3
如果你有缩写词,可能不希望它们之间有空格。这个两阶段的正则表达式将保持缩写词完整(并且还会将标点符号和其他非大写字母视为需要添加空格的内容):
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'

1

我同意正则表达式的解决方案是最简单的,但我不认为它是最具Python风格的。

那么怎么样:

text = 'WordWordWord'
new_text = ''

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

    new_text += letter

这和丹的问题一样 - 即使不需要,在大写字母之前也会得到额外的空格。 - Brian
没错,我已经编辑过了,加了一个标志... 我承认这有点繁琐,但可能比正则表达式更容易记住。 - monkut

0
回到旧的线程 - 想尝试一种选项来满足我的需求。当然,re.sub() 是很酷的解决方案,但如果不应该导入 re 模块,也有一个一行代码的解决方案。
st = 'ThisIsTextStringToSplitWithSpace'
print(''.join([' '+ s if s.isupper()  else s for s in st]).lstrip())

0

我认为正则表达式是解决这个问题的方法,但为了提供一个纯Python版本,避免(希望如此)ΤΖΩΤΖΙΟΥ指出的任何问题:

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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接