在双引号和方括号中拆分字符串

时间:2014-12-04 21:00:29

标签: python string-split

我刚开始使用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('\"')

但这也给出了一个奇怪的输出 说实话我真的不懂正则表达式,也不知道我是否可以像真的一样进口。

2 个答案:

答案 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建议的解析器。