python - 在 Python 中使用正则表达式进行标记化

标签 python regex parsing token tokenize

我尝试标记像 "spam bar ds<hai bye>sd baz eggs" 这样的字符串进入列表['spam', 'bar', 'ds<hai bye>sd', 'baz', 'eggs'] ,即像 str.split()但保留 < ... > 内的空格.

我的解决方案是使用re.split(\S*<.*?>\S*)|\s+图案。但是我得到以下信息:

>>> re.split('(\S*<.*?>\S*)|\s+', "spam bar ds<hai bye>sd baz eggs")
['spam', None, 'bar', None, '', 'ds<hai bye>sd', '', None, 'baz', None, 'eggs']

不确定那些None在哪里s 和空字符串来自。当然,我可以使用列表理解过滤掉它们 [s for s in result if s] ,但在我知道原因之前我不愿意这样做。

那么,(1) 为什么是 None s 和空字符串,(2) 可以做得更好吗?

最佳答案

None和空字符串值是因为您在模式中使用了捕获括号,因此拆分包含匹配的文本 - 请参阅 official documentation提到这一点。

如果您将模式修改为 r"((?:\S*<.*?>\S*)|\S+") (即转义括号以使其不捕获并将空格纠正为非空格)它应该可以工作,但只能通过保留分隔符来实现,然后您需要通过跳过替代项来过滤掉分隔符。我认为你这样做会更好:

ITEM_RE = re.compile(r"(?:\S*<.*?>\S*)|\S+")
ITEM_RE.findall("spam bar ds<hai bye>sd baz eggs")

如果您不需要实际的列表(即您一次只浏览一项),则 finditer()效率更高,因为它一次只产生一个。如果您可能在不查看整个列表的情况下退出,则尤其如此。

原则上也有可能使用否定的后向断言,但实际上我认为不可能创建一个足够灵活的 - 我尝试过 r"(?<!<[^>]*)\s+"并收到错误“后视需要固定宽度模式”,所以我想这是一个禁忌。文档证实了这一点 - 后向断言(正面和负面)都需要固定宽度。

这种方法的问题在于,如果您期望嵌套尖括号 - 那么您将无法得到您所期望的结果。例如解析ds<hai <bye> foo>sd将产生ds<hai <bye>作为一个 token 。我认为这是正则表达式无法解决的一类问题 - 您需要更接近正确解析器的东西。用纯 Python 编写一个每次遍历字符并计算括号嵌套级别的程序并不难,但这会很慢。取决于您是否可以确定您只会在输入中看到一层嵌套。

关于python - 在 Python 中使用正则表达式进行标记化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15280577/

相关文章:

python - 给定同样的一段代码,为什么 python 版本比 C 慢 100x+?

javascript - 用 SPAN 标签包围 HTML 文本中的单个单词?

regex - sed错误: "invalid reference\1 on ` s' command's RHS"

html - 在 VBA 中将 html 转换为纯文本

java - XML 搜索和解析

python - 如果值出现在基于一个列值的另一个数据框中,则更改一个数据框中的值

python - 如何在 Jupyter notebook 中查看模块的源代码?

python - 气泡图加权二维散点图数据到网格/网格

javascript - 确定字符串是否至少有 2 个来自数组的相同元素

json - Flutter 使用健全的 null 安全性将多级 JSON 解析为类