【问题标题】:Parsing in Python: what's the most efficient way to suppress/normalize strings?在 Python 中解析:抑制/规范化字符串的最有效方法是什么?
【发布时间】:2009-05-11 05:55:03
【问题描述】:

我正在解析一个源文件,我想“抑制”字符串。我的意思是将每个字符串(如“bla bla bla +/*”)转换为“字符串”之类的确定性且不包含任何可能混淆我的解析器的字符,因为我不关心字符串。这里的问题之一是使用例如字符串格式化。 “%s”,请参阅下面我对此的评论。

以下面的伪代码为例,它可能是我正在解析的文件的内容。假设字符串以 " 开头,转义 " 字符由 "" 完成:

print(i)
print("hello**")
print("hel"+"lo**")
print("h e l l o "+
"hello\n")
print("hell""o")
print(str(123)+"h e l l o")
print(uppercase("h e l l o")+"g o o d b y e")

应该转化为如下结果:

print(i)
print("string")
print("string"+"string")
print("string"
"string")
print("string")
print(str(123)+"string")
print(uppercase("string")+"string")

目前,我将其视为代码中的一种特殊情况(即检测字符串的开头,并“手动”运行直到结束,途中有几个子特殊情况)。如果有一个我可以使用的 Python 库函数或一个不错的正则表达式可以使我的代码更高效,那就太好了。

几点说明:

  • 我希望“字符串开头”字符是一个变量,例如' 与 "。
  • 在这个阶段我不解析 Python 代码,但我计划这样做,问题显然变得更加复杂,因为字符串可以以多种方式开始,并且必须以与开始相对应的方式结束。我现在不打算处理这个问题,但如果有任何成熟的最佳实践,我想知道它。
  • 关于这种“抑制”,最困扰我的是字符串格式化与“%s”之类的情况,它们是有意义的标记。我目前没有处理这个问题,也没有完全考虑清楚,但是如果你们中的任何人对如何处理这个问题有任何建议,那就太好了。请注意,我对字符串内标记的特定类型或格式不感兴趣,我知道字符串中有标记(有多少)就足够了。此处可能很重要的注释:我的标记器没有嵌套,因为我的目标很简单(我没有编译任何东西......)。
  • 我不太确定起始字符串字符的转义。你会说在大多数编程语言中实现这一点的常见方式是什么?重复出现(例如“”)或任何两个字符集(例如'\"')的假设是否足以转义?我是否需要处理其他情况(想想像 Java、C/C++、PHP、C# 这样的语言)?

【问题讨论】:

  • 这个问题看起来很奇怪。您是否使用正则表达式来解析 python 而不是解析器生成器(例如使用 pyparsing)?提供一些关于您正在做的事情的更大图景的见解会很有帮助。
  • 我正在对多种语言的代码文件进行标记。我没有将正则表达式用于“大图”,但我确实使用了几个正则表达式来解决特定问题,例如删除 cmets,空白行等。我希望澄清一下。

标签: python string parsing


【解决方案1】:

选项 1:要清理 Python 源代码,请尝试内置 tokenize 模块。它可以在任何 Python 源文件中正确查找字符串和其他标记。

选项 3:将 pygments 与 HTML 输出一起使用,并将蓝色(等)的任何内容替换为 "string"。 pygments 支持几十种语言。

选项 2:对于大多数语言,您可以构建自定义正则表达式替换。例如,以下内容会清理 Python 源代码(但如果源文件包含 """''',则它不起作用):

import re
sanitized = re.sub(r'(#.*)|\'(?:[^\'\\]+|\\.)*\'|"(?:[^"\\]+|\\.)*"',
    lambda match: match.group(1) or '"string"', source_code)

即使字符串包含反斜杠(\"\\\n\\\\"\\\" 等都可以正常工作),上面的正则表达式也能正常工作。

在构建正则表达式时,请确保匹配 cmets(这样您的正则表达式替换不会触及 cmets 内的字符串)和正则表达式文字(例如在 Perl、Ruby 和 JavaScript 中),并注意匹配反斜杠和换行符正确(例如,在 Perl 和 Ruby 中,字符串可以包含换行符)。

【讨论】:

  • 我认为内置的 tokenize 只对 Python 代码有用,对 C++/Java/etc 无效?
  • 当然,tokenize 仅适用于 Python 代码。为其他语言的代码添加了更多提示。
  • 代码不起作用,我在例如print("hello") 并返回 print("hello")。有什么建议吗?
  • @pts: 抱歉,'print("hello")' 仍然无法工作。谢谢。
  • 编辑了我的答案:更改为 match.group(1)。现在它应该可以工作了。
【解决方案2】:

为每种语言使用专用解析器——尤其是因为人们已经为您完成了这项工作。您提到的大多数语言都有语法。

【讨论】:

  • 我希望他们有语法;)
【解决方案3】:

您在任何地方都没有提到您使用lexerparser 的方法。如果实际上您没有,请查看例如tokenize 模块(这可能是您想要的),或第 3 方模块 PLY(Python Lex-Yacc)。您的问题需要一种系统的方法,而这些工具(和其他工具)提供了它。

(请注意,一旦您对代码进行了标记,您可以将另一个专门的标记器应用于字符串的内容,以检测特殊的格式化指令,例如%s。在这种情况下,正则表达式可能不过,做这项工作。)

【讨论】:

    猜你喜欢
    • 2010-12-17
    • 2013-03-08
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 2012-07-28
    • 1970-01-01
    相关资源
    最近更新 更多