今天跟大家唠唠我在实际工作中折腾正则表达式匹配空格的那些事儿。这玩意儿,说难不难,说简单也真不简单,尤其是要考虑各种奇奇怪怪的情况,那叫一个头大。
我接个小任务,就是要把用户输入的一段文本里多余的空格给清理掉。心想这还不简单?直接抄起 `\s+` 就怼上去。`\s` 嘛大家都知道,匹配任何空白字符,包括空格、制表符、换行符等等,后面的 `+` 表示匹配一个或多个。
python
import re
text = "Hello World! "
cleaned_text = *(r"\s+", " ", text)
print(cleaned_text) # 输出:Hello World!
看起来不错,对?但很快就发现问题。有些地方只需要保留一个空格,有些地方则需要完全移除。比如,我需要把句首和句尾的空格都去掉,但句子中间的连续空格只保留一个。
然后我就开始各种查资料、试错。发现 `\s` 这个东西也挺有用。`\s` 表示匹配零个或多个空格。但我不能直接用它替换,因为那样会把所有空格都干掉。
后来我找到一个比较靠谱的方案,就是用 `*` 结合一些更精确的正则表达式。
去除句首和句尾的空格,可以用 `^` 和 `$` 分别表示字符串的开头和结尾。`^\s+` 匹配句首的多个空格,`\s+$` 匹配句尾的多个空格。
python
import re
text = " Hello World! "
cleaned_text = *(r"^\s+\s+$", "", text)
print(cleaned_text) # 输出:Hello World!
要处理句子中间的连续空格,只保留一个。这个稍微麻烦一点,但可以用 `\s{2,}` 来匹配两个或更多个空格。
python
import re
text = "Hello World! "
cleaned_text = *(r"\s{2,}", " ", text)
print(cleaned_text) # 输出:Hello World!
把这两个操作结合起来,就得到最终的解决方案:
python
import re
def clean_spaces(text):
text = *(r"^\s+\s+$", "", text) # 去除句首和句尾的空格
text = *(r"\s{2,}", " ", text) # 将多个连续空格替换为一个空格
return text
text = " Hello World! "
cleaned_text = clean_spaces(text)
print(cleaned_text) # 输出:Hello World!
但是,问题又来!用户输入的文本里可能包含各种奇葩的空白字符,比如制表符(`\t`)、换行符(`\n`)、回车符(`\r`)等等。如果只用 `\s`,可能会把这些字符也当成空格处理掉,导致意想不到的结果。
为更精确地匹配空格,我尝试使用 `[ ]`。在正则表达式里,`[ ]` 表示匹配方括号内的任何一个字符。`[ ]` 就只会匹配真正的空格字符,而不会匹配制表符、换行符之类的东西。
python
import re
text = "Hello\tWorld!\n"
# 只替换空格,不替换制表符和换行符
cleaned_text = *(r"[ ]{2,}", " ", text)
print(cleaned_text) # 输出:Hello World! (制表符和换行符还在)
但是,这种方法也有局限性。如果用户输入的文本里包含其他类型的空白字符,就需要更复杂的正则表达式来处理。
我决定采用一种更灵活的方法,就是先将所有类型的空白字符都替换成空格,然后再用上面的方法清理空格。
python
import re
def clean_all_spaces(text):
text = *(r"[\t\n\r]", " ", text) # 将制表符、换行符、回车符替换成空格
text = *(r"^\s+\s+$", "", text) # 去除句首和句尾的空格
text = *(r"\s{2,}", " ", text) # 将多个连续空格替换为一个空格
return text
text = " Hello\tWorld!\n "
cleaned_text = clean_all_spaces(text)
print(cleaned_text) # 输出:Hello World!
这样,基本上就可以处理各种奇葩的空格情况。
这回折腾正则表达式的经历告诉我,看似简单的任务,背后可能隐藏着各种各样的坑。只有不断学习、实践、才能真正掌握这些看似不起眼的小技巧。