【问题标题】:Python regex module "re" match unicode characters with \uPython 正则表达式模块“re”将 unicode 字符与 \u 匹配
【发布时间】:2022-01-19 11:33:34
【问题描述】:

我正在尝试从我正在处理的字符串中识别和替换 unicode 字符以制作关键字匹配过滤器。

例如,给定字符串

"Apple iPhone 12 mini A2176 128GB\u00a0(PRODUCT) Red!\u00a0Perfect condition! Unlocked!"

我希望使用 re.sub 函数时的输出(用空格“”替换模式)是

"Apple iPhone 12 mini A2176 128GB (PRODUCT) Red! Perfect condition! Unlocked!"

所以我去了一个正则表达式 build and test website 并想出了这个模式

\\u[a-z|0-9]{4}

捕获 2 个 unicode 字符串

\u00a0 and \u00a0

现在尝试将它应用到我的 python 代码中,我首先尝试了这个 sn-p。这里我使用findall函数来查看代码是否会返回unicode字符串

import re

strin = "Apple iPhone 12 mini A2176 128GB\u00a0(PRODUCT) Red!\u00a0Perfect condition! Unlocked!"


print(re.findall('\\u[a-z|0-9]{4}', strin))

导致以下错误返回

re.error: incomplete escape \u at position 0

然后我尝试在字符串模式前添加一个“r”。没有出现错误但是没有返回unicode字符串

print(re.findall(r'\\u[a-z|0-9]{4}', strin))

输出是一个空列表[] 然后我尝试了相同的 2 种方法,但只有 1 个反斜杠

print(re.findall('\u[a-z|0-9]{4}', strin))SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: truncated \uXXXX escape

print(re.findall(r'\u[a-z|0-9]{4}', strin)) gives 
re.error: incomplete escape \u at position 0

【问题讨论】:

  • \u00a0 是一个不间断的空格。如果您只需要用常规 ASCII 空格替换不间断空格,请仅使用 strin.replace('\u00a0', ' ')
  • 您对输入字符串感到困惑。它包含单个 Unicode 字符 \u00a0(也称为 NO-BREAK SPACE),而不是五个字符反斜杠、u、零、零、a、零。
  • @WiktorStribiżew 我的代码还必须处理其他 unicode 字符串,例如“\ud83d”

标签: python regex re


【解决方案1】:

您在这里有多个误解(所有这些都是常见的常见问题解答)。

re.findall 的参数是一个字符串。在 Python 中,字符串中的反斜杠必须通过加倍来转义。更好的解决方案是使用r"..." 原始字符串表示法,特别是对于正则表达式,它通常需要包含实际正则表达式的文字反斜杠。

您从findall 收到的错误消息告诉您,字符转义\u[ 不正确,因为[ 不是十六进制数字。 (事实上​​,即使你的正则表达式在语法上没有错误,它也匹配得太多了;Python 中 Unicode 字符转义的正则表达式应该是 \\u[0-9a-f]{4},而不是 a-z。)

字符 \u00a0 是单个 Unicode 字形,在字符串中包含单个字符。你不能用这样的正则表达式来匹配它。你可以匹配的是例如

re.findall(r'[\u0080-\uffef]', strin)

它包含一个字符类,涵盖 Unicode 基本多语言平面中的非 ASCII 字符范围(包括代理,正确地说我们应该排除,但我们不要去那里回答初学者问题。也许还要注意,有 Unicode BMP 以外的字符,可以匹配[\U00010000-\U0010FFFF])。

(顺便说一句,还要注意字符类[a-z|0-9] 在字符类中包含文字字符|| 代表交替在字符类之外,但在[ 内...] 除了初始的^- 之外的所有内容都只是一个文字字符。)

但更根本的是,初学者对“我不明白这个 Unicode 东西”的反应是错误的;响应应该是“我需要了解这些东西”,而不是“我需要删除它”。简单地删除所有 Unicode 几乎没有什么好的案例,而且这种趋势只会把你拖回 Unicode 之前的黑暗时代,那时你只能在西方计算机中表示英文文本(而且几乎没有)。

针对这个特定问题的更原则性解决方案是将所有空白字符(可能除了制表符)规范化为 ASCII 空间,并在遇到其他 Unicode 字符时弄清楚如何处理它们。什么是有意义的很大程度上取决于您的特定应用程序。对于搜索或 NLP,将所有文本规范化或“展平”为接近 ASCII 的子集可能是有意义的,但对于许多其他应用程序,您通常需要一些更细微的东西。

不碍事,试试

Python 3.8.2 (default, May 18 2021, 11:47:11) 
[Clang 12.0.5 (clang-1205.0.22.9)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> strin = "Apple iPhone 12 mini A2176 128GB\u00a0(PRODUCT) Red!\u00a0Perfect condition! Unlocked!"
>>> import re
>>> re.sub(r'\s', ' ', strin)
'Apple iPhone 12 mini A2176 128GB (PRODUCT) Red! Perfect condition! Unlocked!'

【讨论】:

  • 如果这解决了您的问题,请考虑接受它。或者,您可以发布自己的答案并接受。接受答案通过将问题标记为已解决来帮助未来的访问者。另见help.
  • 如果没有,您能否edit 澄清您的目标到底是什么?
【解决方案2】:

如果您的目的只是从文本中删除 unicode,那么您的工作就太辛苦了。您可以简单地使用

strin.encode('ascii', 'ignore').decode('ascii')

您将字符串编码为 ascii 并忽略错误,然后将其再次解码为 ascii 从而删除所有非 ascii 字符

【讨论】:

  • 这样的问题是,对于上面的输入字符串,它会导致每个 unicode 旁边的 2 个字符串变成 1 个字符串,所以“128GB\u00a0(PRODUCT)”会变成“128GB(PRODUCT)” “128GB(产品)”
  • @Gamewatch 是的,这是一个简单的剥离解决方案。如果你想用特定的东西替换 unicode,你可能必须使用某种映射
猜你喜欢
  • 2023-02-07
  • 2013-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多