5

这最终会变得非常简单,但我正在尝试匹配两种模式之一:

"GET /ligonier-broadcast-media/mp3/rym20110421.mp3 HTTP/1.1"

或者

-

我试过这样的事情:

key = Word(alphas + nums + "/" + "-" + "_" + "." + "?" + "=" + "%" + "&")

uri = Or("-" | Group(
                   Suppress("\"") +
                   http_method +
                   key.setResultsName("request_uri") +
                   http_protocol +
                   Suppress("\"")
               )
      )

但它似乎不匹配。我完全不确定如何使用 Or(),如果我应该使用 Group(),或者什么。我知道 Group() 类中提供的参数如果单独调用就可以工作,但我真的需要破折号或带引号的 URI 字符串,而不仅仅是一个。

无法协商日志格式,我们正在消耗我们得到的东西。任何提示将非常感谢。

4

2 回答 2

19

一般来说,Or、And、MatchFirst 和 Each 类很少在 pyparsing 中公开使用。推荐的风格是使用它们类似的运算符重载。在您的情况下,您正在使用这两种形式,它只是妨碍您。

这是你的表达,经过一点清理:

key = Word(alphanums + "/-_.?=%&")
QUOT = Suppress('"')
uri = ("-" | QUOT
             + http_method
             + key("request_uri")
             + http_protocol
             + QUOT
      )

Word 的参数是表示允许的字符集的字符串。如果只使用一个参数(如您的情况),则字符串被解释为简单的字符集,可以作为 Word 的一部分进行解析。如果给出 2 个字符串,则第一个表示可接受的初始字符集,第二个是可接受的主体字符集(在定义变量名之类的东西时很有用,例如在 Python 中只允许使用字母和 '_'初始字符,但也允许在正文中出现数字。这将是Word(alphas+'_', alphanums+'_')。由于 Word 的参数只是字符串,因此无需单独添加"/" + "-" + "_" + ...,只需将它们组合成一个字符串即可。

'|' 运算符分隔允许的备选方案,生成 MatchFirst 表达式。之所以称为 MatchFirst,是因为解析器将在第一个给定表达式匹配后停止尝试。因此,如果用 解析字符串“abc” Word(alphas) | Word(nums),pyparsing 甚至不会尝试匹配Word(nums)表达式 - 第一个替代匹配。如果您想要的内容有一些重叠,这会变得更加棘手。假设您要匹配字母词、字母词或字母和字母词,并且要解析字符串“abc123”。这个解析器:

Word(alphas) | Word(nums) | Word(alphanums)

将解析带有前导的字符串的开头 'abc' Word(alphas)。我们通常可以通过重新安排替代方案来解决此类问题,例如:

Word(alphanums) | Word(alphas) | Word(nums)

但并非所有情况都如此容易重构。所以 pyparsing 还支持 Or 表达式,使用 '^' 运算符定义(我选择它是因为 '^' 让我想起一对绘图员的分隔线,用于测量长度)。Or 表达式尝试应用所有给定的备选方案,并选择最长的匹配项。因此,您可以将我的小测试示例编写为:

Word(alphas) ^ Word(nums) ^ Word(alphanums)

现在 pyparsing 在匹配“abc”时不会停止,而是会尝试所有替代方案,并最终选择第三个替代方案,匹配“abc123”,因为它提供了更长的匹配。

对于你的 URI 定义,不需要做 Or 匹配。解析器不会将前导“-”与带引号的 HTTP 命令字符串混淆。所以使用 MatchFirst,你已经通过使用 '|' 运营商,完全够用。

其他一些项目:

  • "\""如果可以,请不要使用 Python 编写代码。出于这个原因,Python 支持这两种引用字符。改为使用'"'。反斜杠用于 C 程序员和 Windows 文件名。

  • expr.setResultsName("name")expr("name")自 pyparsing 1.4.6 以来已简化为。缩短的语法确实有助于您的解析器定义的可读性。

  • 仅当您希望在结果中保留某些结构,或者如果您有一个重复结构,其中包含带有结果名称的某些内部表达式时,才使用 Group。您的解析器并不真正需要,只需在结果上添加另一个列表容器包装器,需要一个额外的[0]索引来获取您解析的数据。

(如果您确实决定要显式调用Or,And等,请确保传递表达式列表,并且不要仅将它们列为表达式构造函数的参数 - 请参阅Why is ordered choice in pyparsing failed for my use案例?关于这样的拼写错误会如何搞砸事情,这就是为什么我鼓励使用算术运算符来组成你的解析器。)

于 2011-04-27T10:32:14.937 回答
1

我想你想要...

from pyparsing import oneOf
# more code here
uri = oneOf(["-", <insert long match expr here>])`
uri.matchString(someStringVar)
于 2011-04-27T03:55:35.400 回答