【问题标题】:adding spaces inside string using regex sub使用正则表达式子在字符串内添加空格
【发布时间】:2016-07-28 07:52:17
【问题描述】:

我有一个字符串,我想将其拆分为两位数。我尝试像这样使用正则表达式:

import re
s = "123456789"
t = re.sub('..', ".. ", s)
print(t)

我希望得到12 34 56 78 9,但我得到了'.. .. .. .. 9'9 不会打扰我,因为我知道我会有偶数位数,但我如何告诉 re.sub 不要用点替换实际数字?

使用 python shell 3.5.1

编辑

检查了所有 3 个答案,它们都有效,但 findall 似乎更快(并且更优雅的 IMO ;p):

import time
import re

s = "43256711233214432"

i = 10000
start = time.time()
while i:
    i -= 1
    re.sub('(..)', r"\1 ", s)    
end = time.time()

elapsed = end - start
print("using r\"\\1 \"    : ", elapsed)

i = 10000
start = time.time()
while i:
    re.sub('..', r"\g<0> ", s)
    i -= 1
end = time.time()

elapsed = end - start
print("using r\"\g<0> \" : ", elapsed)

i = 10000
start = time.time()
while i:
    ' '.join(re.findall(r'..|.', s))
    i -= 1
end = time.time()

elapsed = end - start
print("using findall   : ", elapsed)

使用 r"\1" : 0.25461769104003906

使用 r"\g" : 0.09374403953552246

使用 findall : 0.015610456466674805

第二次编辑:有没有更好的方法(或任何方法......)这样做没有正则表达式?

【问题讨论】:

  • 你的时序分析很奇怪。 \1\g&lt;0&gt; 做的差不多,应该同样快。使用 IPython 的 %timeit 函数,sub 方法都为我提供了 8.5µs,findall 为 2.0µs,range(0, len, 2) 为 1.5µs
  • @tobias_k 不知道...我运行这个脚本大约 10 次,每次 "findall" 是第 1 次,"g" 第 2 次和 "\1" 第 3 次
  • 如果你以不同的顺序测试它们会发生什么,首先是\g,然后是\1findall 是最快的(range 除外),无需争论。顺便说一句,当我运行你的脚本时,它更接近于 %timeit\g\1 几乎相同。
  • 我看到了细微的变化,但不确定它们......我让它连续运行了 10 次,并且做得很平均。 g 两次都快了 0.2

标签: python regex


【解决方案1】:

您也可以使用re.findall

>>> s = "123456789"
>>> ' '.join(re.findall(r'..|.', s))
'12 34 56 78 9'
>>> 

r'..|.' 正则表达式匹配两个字符或单个字符(首选是..,然后是.

【讨论】:

  • ... 但不切实际 - 为什么要通过 2 个步骤 (re.findall + join) 来实现结果,而您可以使用 1 个步骤 (re.sub) 来实现。此外,具有交替性能的正则表达式比没有性能要慢。
  • @WiktorStribiżew '具有交替性能的正则表达式更慢......'是什么意思?根据我的测试,这种方法目前速度更快
  • re.sub('..', r"\g&lt;0&gt; ", s)快吗?
【解决方案2】:

您可以在替换字符串模式中使用\g&lt;0&gt; backreference 引用整个匹配项(您不能使用正则表达式 模式):

re.sub('..', r"\g<0> ", s)

Python demo:

import re
s = "12345678"
print(re.sub('..', r"\g<0> ", s))

re.sub reference:

反向引用\g&lt;0&gt; 替换为RE 匹配的整个子字符串。

【讨论】:

    【解决方案3】:

    在正则表达式中,. 表示任何字符。在替换文本中,它表示句号。如果你想在你的正则表达式中捕获字符作为一个组,你需要在它们周围加上括号。您可以使用\1 引用替换文本中的第一个此类组:

    >>> re.sub('(..)', r"\1 ", s)
    '12 34 56 78 9'
    

    【讨论】:

      【解决方案4】:

      您也可以使用 List Comprehensions,

      >>> s='123456789'
      >>> res=[s[index:index+2] for index,x in enumerate(s) if index % 2==0]
      ['12', '34', '56', '78', '9']
      

      【讨论】:

      • 但这给出了列表,而不是字符串,并且没有空格
      • @noob 它给出的结果与findall 相同,你只需要' '.join。但是,与其他解决方案相比,它有点笨拙。
      • 我建议你使用' '.join(s[i:i+2] for i in range(0, len(s), 2)),而不是enumerate 和那个模检查。
      猜你喜欢
      • 1970-01-01
      • 2013-10-07
      • 1970-01-01
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多