【问题标题】:Splitting string with delimiter one and index[0] with other使用分隔符 1 和索引 [0] 分割字符串
【发布时间】:2016-02-15 01:15:58
【问题描述】:

如何在不创建两个列表和附加的情况下拆分这个多重分隔符,这似乎是非常影响性能的操作。

string = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV'

string.split("|")[0].split(".") + string.split("|")[1:]
Out[156]: ['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV']

简单的re.split(r'[.|]') 不起作用,因为在字符串的第二部分。

string = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV|D|F.g|.Y|'

re.split(r'[./|]', string)
Out[179]: ['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'D', 'F', 'g', '', 'Y', '']

数据NOPQ 和RSTUV 可能包含.,但它不是分隔符。管道分隔列的数量可能会增加。但是,总是直到第一个 |,分隔符 . 在第一个 | 之后是分隔符,只有 | 是分隔符。

数据可能是其他几种可能的组合,

string = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV|DFGR'
string.split("|")[0].split(".") + string.split("|")[1:]
Out[174]: ['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'DFGR']

string = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV|D.F.GR.'
string.split("|")[0].split(".") + string.split("|")[1:]
Out[176]: ['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'D.F.GR.']

string = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV|D|F.g|.Y|'
string.split("|")[0].split(".") + string.split("|")[1:]
Out[178]: ['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'D', 'F.g', '.Y', '']

    string = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV|D|F.g|Y|H|J|K|R|Y' 
string.split("|")[0].split(".") + string.split("|")[1:]
Out[181]: ['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'D', 'F.g', 
'Y', 'H', 'J', 'K', 'R', 'Y']

【问题讨论】:

  • 尝试this demo - 不知道是否反转字符串并使用普通的re 模块会加快速度,但它是regex 模块的另一种替代方案。
  • @stribizhev 谢谢我试过,即使这很慢。我实际上每天解析 20 M 条记录的日志。这只是玩具数据,实际上有 35 到 62 列拆分
  • 我明白了。很可惜Pythonre不支持\G。
  • @stribizhev:我只是意识到没有必要 \G 锚...哎呀。
  • @CasimiretHippolyte:我知道它可以通过可变宽度的后视来完成。同样,除了 .NET 之外,我在任何地方都想念一些东西(好吧,不是在谈论基于 ICU 的正则表达式引擎的受限宽度后视)。

标签: python regex python-2.7 parsing


【解决方案1】:

新答案:

使用 re 模块:

>>> import re
>>> s = 'ABCD..EFGH.IJKLM|NOPQ|RSTUV|D|F.g|Y|H|J|K|R|Y||'
>>> re.findall(r'(?<=\|)[^|]*|(?:(?<=\.)|\A)[^|.]*', s)
['ABCD', '', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'D', 'F.g', 'Y', 'H', 'J', 'K', 'R', 'Y', '', '']

旧答案:

使用new regex module,您可以这样做:

>>> import regex
>>> s = 'ABCD.EFGH.IJKLM|NOPQ|RSTUV|D|F.g|Y|H|J|K|R|Y'
>>> regex.findall(r'\G\.?\K[^.|]+|[^|]+', s)
['ABCD', 'EFGH', 'IJKLM', 'NOPQ', 'RSTUV', 'D', 'F.g', 'Y', 'H', 'J', 'K', 'R', 'Y']

demo

其中\G 匹配字符串的开头或上一个匹配之后的下一个位置,\K 从匹配结果中丢弃左侧的所有字符(此处为可选点)。

\G 用于强制所有结果在第一个管道之前是连续的。由于没有与模式中的管道匹配,因此连续性被破坏,第二个分支 [^|]+ 用于其他项目。

注意:以同样的方式,您可以选择使用此模式确保字符串第二部分的连续性:\|\K[^|]+|[^|.]+ (如果字符串的第二部分包含很多项目,这可能会很有趣)。但是这次不需要使用\G 锚,因为每个连续的项目前面都有一个管道。

注意2:如果要考虑空项目,可以将模式更改为:

regex.findall(r'\G(?:\A|\.)\K[^.|]*|[^|]+|(?<=\|)', s)

或

regex.findall(r'\|\K[^|]*|(?:\.|\A)\K[^|.]*', s)

【讨论】:

    【解决方案2】:

    使用re 模块。使用 re.split 应该可以解决问题,例如re.split('[|.]', string)

    【讨论】:

      猜你喜欢
      • 2022-01-18
      • 2013-05-03
      • 1970-01-01
      • 2013-08-16
      • 2021-06-12
      • 2013-11-24
      • 2011-03-26
      相关资源
      最近更新 更多