【问题标题】:Regex should handle whitespace including newline differently正则表达式应该以不同的方式处理空格,包括换行符
【发布时间】:2015-08-24 18:00:09
【问题描述】:

我的目标是制作一个可以处理两种情况的正则表达式:

  • 包含一个或多个任意顺序的换行符的多个空格应成为一个换行符
  • 不包括任何换行符的多个空格应成为空格

无序性与换行符和无换行符的不同情况相结合,使这变得复杂。

最有效的方法是什么?

例如

'   \n \n \n a'     # --> '\na'
'   \t \t    a'     # --> ' a'  
'   \na\n     '     # --> '\na\n'

基准测试:

s = '   \n \n \n a   \t \t    a   \na\n     '
n_times = 1000000
------------------------------------------------------
change_whitespace(s)   - 5.87 s
change_whitespace_2(s) - 3.51 s
change_whitespace_3(s) - 3.93 s

n_times = 100000
------------------------------------------------------
change_whitespace(s * 100)    - 27.9 s 
change_whitespace_2(s * 100)  - 16.8 s 
change_whitespace_3(s * 100)  - 19.7 s    

【问题讨论】:

  • 荒谬。这个问题怎么太笼统了?
  • 我唯一能想到的是你没有展示你尝试过的东西,但这并不一定让它本身太宽泛,所以我不知道。跨度>
  • 一个很好的问题,我也想过两步法,但无法使用 PC。请不要忘记接受对您有用的答案:)

标签: python html regex


【解决方案1】:

(假设 Python 可以用回调函数进行正则表达式替换)

您可以使用一些回调来查看需要替换的内容。
第 1 组匹配,用空格替换。
第 2 组匹配,用换行符替换

(?<!\s)(?:([^\S\r\n]+)|(\s+))(?!\s)

 (?<! \s )           # No whitespace behind
 (?:
      ( [^\S\r\n]+ )      # (1), Non-linebreak whitespace
   |  
      ( \s+ )             # (2), At least 1 linebreak
 )
 (?! \s )            # No whitespace ahead

【讨论】:

  • 非常好,就像@TigerhawkT3 建议的那样。我很惊讶他没有 +1 你。我会接受他的答案,因为这是 Python 答案,但他肯定欠 +1。
  • 我不是 regexpert,所以在我理解这个答案中的技术之前需要更多的研究。
  • 对于替换函数,它的简单(?&lt;!\s)(?:([^\S\r\n]+)|\s+)(?!\s) 如果匹配组(1)替换为空格,否则换行...不懂 Python。
  • 哦,我明白了 - 我正在做相反的事情并检查 group(0) 匹配,但它是第二组可能匹配也可能不匹配。
  • 只有组 1 或组 2 会匹配(不能同时匹配),只需要检查单个组是否匹配。
【解决方案2】:

这会将包含换行符的空格替换为单个换行符,然后将不包含换行符的空格替换为单个空格。

import re

def change_whitespace(string):
    return re.sub('[ \t\f\v]+', ' ', re.sub('[\s]*[\n\r]+[\s]*', '\n', string))

结果:

>>> change_whitespace('   \n \n \n a')
'\na'
>>> change_whitespace('   \t \t    a')
' a'
>>> change_whitespace('   \na\n     ')
'\na\n'

感谢@sln 提醒我正则表达式回调函数:

def change_whitespace_2(string):
    return re.sub('\s+', lambda x: '\n' if '\n' in x.group(0) else ' ', string)

结果:

>>> change_whitespace_2('   \n \n \n a')
'\na'
>>> change_whitespace_2('   \t \t    a')
' a'
>>> change_whitespace_2('   \na\n     ')
'\na\n'

这是一个带有@sln 表达式的函数:

def change_whitespace_3(string):
    return re.sub('(?<!\s)(?:([^\S\r\n]+)|(\s+))(?!\s)', lambda x: ' ' if x.group(1) else '\n', string)

结果:

>>> change_whitespace_3('   \n \n \n a')
'\na'
>>> change_whitespace_3('   \t \t    a')
' a'
>>> change_whitespace_3('   \na\n     ')
'\na\n'

【讨论】:

  • 回调的速度明显更快!不知道第二个参数可能是一个函数。
  • if '\n' in x.group(0) 可疑地看起来像是在重新扫描相同的东西。
  • 第二个版本更快(并且仍然正确)。测试字符串是连接所有 3 个示例,运行了 100 万次。
  • 第三版怎么样?
  • 这些是有趣的计时结果。我猜这两张小支票比一张大支票要快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多