我刚开始使用Python,我正在尝试用双引号和方括号分割字符串。
示例:
10.223.157.186 - - [15/Jul/2009:14:58:59 -0700] "GET /assets/js/lowpro.js HTTP/1.1" 200 10469
通缉结果:
ip: 10.223.157.186
identity: -
username: -
time: [15/Jul/2009:15:50:35 -0700]
request: "GET /assets/js/lowpro.js HTTP/1.1"
status: 200
size: 10469
我想将它们拆分为“空格”,但它也会在[]
和""
之间拆分。像这样:
['10.223.157.186', '-', '-', '[15/Jul/2009:14:58:59', '-0700]', '"GET', '/assets/js/lowpro.js', 'HTTP/1.1"', '200', '10469']
我见过许多可能的解决方案,如:
shlex
(我的python不导入它)data = line.strip().split('\"')
但这也给出了一个奇怪的输出 说实话我真的不懂正则表达式,也不知道我是否可以像真的一样进口。
答案 0 :(得分:2)
我要反对"正则表达式""并说要使用解析器;解析器是高于正则表达式的复杂程度,通常使用正则表达式来定义其语法的一部分。我选择的库是pyparsing
。你可以这样使用它:
>>> s = '10.223.157.186 - - [15/Jul/2009:14:58:59 -0700] "GET /assets/js/lowpro.js HTTP/1.1" 200 10469'
>>> from pyparsing import ZeroOrMore, Regex
>>> parser = ZeroOrMore(Regex(r'\[[^]]*\]') | Regex(r'"[^"]*"') | Regex(r'[^ ]+'))
>>> for i in parser.parseString(s): print i
...
10.223.157.186
-
-
[15/Jul/2009:14:58:59 -0700]
"GET /assets/js/lowpro.js HTTP/1.1"
200
10469
请注意,令牌的顺序(那些Regex
对象的东西)很重要。通过首先放置方括号和双引号,它们优先。如果你把最后一个放在第一位,它就无法正常工作。这样做的一个不错的特性就是它更容易扩展到比正则表达式更复杂(它只支持常规语言操作,除非你做了一堆疯狂的环顾四周的东西)。例如,如果您决定要使用,解析器可以帮助您拆分这些括号或引号内的部分,只需稍加工作,您就可以更改解析器以允许嵌套括号或引号。 (后者是真正的正则表达式无法做到的事情。你可能能够获得带有环视扩展的正则表达式来做到这一点,但在我看来它并不值得。解析器更强大,根据我的经验,更容易理解和使用。)
请注意,解析器不会返回列表或可迭代。它返回自己的特殊对象:
>>> parser.parseString(s)
(['10.223.157.186', '-', '-', '[15/Jul/2009:14:58:59 -0700]', '"GET /assets/js/lowpro.js HTTP/1.1"', '200', '10469'], {})
>>> type(parser.parseString(s))
<class 'pyparsing.ParseResults'>
我想我也应该解释一下我的正则表达式。
\[[^]]*\]
:这只是匹配一对方括号,可选地在它们之间有一些东西。 \[
说它需要以方括号开头。 [^]]
是字符类(只是正则表达式中的一组字符);外括号使它成为一个字符类。 ^
告诉它&#34;其他任何与角色列表中的内容相关的内容,&#34;内部]
只是字符列表。所以除了]
&#34;之外,其他部分只是&#34;。 *
表示&#34;前一个零或更多,&#34;所以它意味着除了]
&#34;之外的零个或多个字符。最后是\]
,这意味着它需要以]
结尾。最初的[
和最终]
必须使用\
进行转义,因为它们通常用于表示字符类。
"[^"]*"
:这与上一个几乎相同。 "
说它必须以双引号开头。 [^"]
与以前的字符类相同;它意味着&#34;除了双引号之外的任何东西&#34;。 *
仍然意味着&#34;零或更多&#34;。最后的"
只意味着必须以引用结束。所以这只是&#34;由双引号括起来的零个或多个字符&#34;。
[^ ]+
:[^ ]
是另一种类型的角色类。它只是意味着&#34;除了空间之外的任何角色,&#34;因为字符列表是一个空格。 +
表示&#34;之前的一个或多个事物&#34; (类似于*
,除了它至少需要一个)。所以这是一个或多个非空格字符&#34;。
|
对象之间的Regex
运算符只是&#34;或者&#34; - 将不同的标记放在一起,这样解析器只要匹配一个标记就会吐出一个标记这三种可能的代币。
答案 1 :(得分:0)
您可以使用正则表达式:
line = """10.223.157.186 - - [15/Jul/2009:14:58:59 -0700] "GET /assets/js/lowpro.js HTTP/1.1" 200 10469\n"""
import re
log_line = re.compile('(?P<ip>[^ ]*) (?P<identity>[^ ]*) (?P<username>[^ ]*) \\[(?P<time>[^\\]]*)\\] "(?P<request>[^"]*)" (?P<status>[^ ]*) (?P<size>[^ ]*)$')
for key, value in log_line.match(line).groupdict().iteritems():
print "%s: %s" % (key, value)
您也可以使用@ jpmc26建议的解析器。