【问题标题】:Python re.split() keep portions of delimiter as part of first string and other as part of second, etcPython re.split() 将分隔符的一部分保留为第一个字符串的一部分,将其他部分保留为第二个字符串的一部分,等等
【发布时间】:2017-09-14 19:10:30
【问题描述】:

我有一种情况,我想将一长段文本拆分成句子。我有一段工作代码可以根据需要拆分字符串,但是它会删除分隔符(我知道会这样)。现在,我希望能够将这些分隔符保留为输出字符串的一部分(适当地重新分配)。

我的例子是这样的:

import re

strings = ['UT Arlington 1st - Berthiaume reached on a fielding error by ss (0-0). O. Salinas fouled out to 1b (2-1 KBB). Q. Rohrbaugh flied out to cf (2-0 BB). B. Cox fouled out to lf (2-2 KBBKF)',
'Southeast Mo. State 1st - EZELL, T. lined out to 2b (2-2 FBBKFFF). HOLST, D. flied out to lf (0-2 FK). GAGAN, T. struck out swinging (1-2 BKKS).',
'UT Arlington 3rd - J. Minjarez hit by pitch (0-0); RJ Williams advanced to second. Berthiaume popped up to 1b (0-2 KF). O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.']

for s in strings:
        header = re.split(r'[ ][-][ ]', s)
        print(header[0])
        text = re.split(r'([a-z][.][ ][A-Z]|[)][.][ ][A-Z])', header[-1])
        print(text)

当前输出:

UT Arlington 1st
['Berthiaume reached on a fielding error by ss (0-0', '). O', '. Salinas fouled out to 1b (2-1 KBB', '). Q', '. Rohrbaugh flied out to cf (2-0 BB', '). B', '. Cox fouled out to lf (2-2 KBBKF)']
Southeast Mo. State 1st
['EZELL, T. lined out to 2b (2-2 FBBKFFF', '). H', 'OLST, D. flied out to lf (0-2 FK', '). G', 'AGAN, T. struck out swinging (1-2 BKKS).']
UT Arlington 3rd
['J. Minjarez hit by pitch (0-0); RJ Williams advanced to secon', 'd. B', 'erthiaume popped up to 1b (0-2 KF', '). O', '. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.']

我想要的输出:

UT Arlington 1st
['Berthiaume reached on a fielding error by ss (0-0)', 'O. Salinas fouled out to 1b (2-1 KBB)', 'Q. Rohrbaugh flied out to cf (2-0 BB)', 'B. Cox fouled out to lf (2-2 KBBKF)']
Southeast Mo. State 1st
['EZELL, T. lined out to 2b (2-2 FBBKFFF)', 'HOLST, D. flied out to lf (0-2 FK)', 'GAGAN, T. struck out swinging (1-2 BKKS).']
UT Arlington 3rd
['J. Minjarez hit by pitch (0-0); RJ Williams advanced to second', 'Berthiaume popped up to 1b (0-2 KF)', 'O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.']

【问题讨论】:

    标签: python regex string split


    【解决方案1】:

    您可能想看看nltk,而不是使用正则表达式:

    from nltk import sent_tokenize
    
    strings = ['UT Arlington 1st - Berthiaume reached on a fielding error by ss (0-0). O. Salinas fouled out to 1b (2-1 KBB). Q. Rohrbaugh flied out to cf (2-0 BB). B. Cox fouled out to lf (2-2 KBBKF)',
    'Southeast Mo. State 1st - EZELL, T. lined out to 2b (2-2 FBBKFFF). HOLST, D. flied out to lf (0-2 FK). GAGAN, T. struck out swinging (1-2 BKKS).',
    'UT Arlington 3rd - J. Minjarez hit by pitch (0-0); RJ Williams advanced to second. Berthiaume popped up to 1b (0-2 KF). O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.']
    
    needle = " - "
    for string in strings:
        pos = string.find(needle)
        header = string[:pos]
        text = string[pos + len(needle):]
        print(header)   
        print(sent_tokenize(text))
    

    产量:

    UT Arlington 1st
    ['Berthiaume reached on a fielding error by ss (0-0).', 'O. Salinas fouled out to 1b (2-1 KBB).', 'Q. Rohrbaugh flied out to cf (2-0 BB).', 'B. Cox fouled out to lf (2-2 KBBKF)']
    Southeast Mo. State 1st
    ['EZELL, T. lined out to 2b (2-2 FBBKFFF).', 'HOLST, D. flied out to lf (0-2 FK).', 'GAGAN, T. struck out swinging (1-2 BKKS).']
    UT Arlington 3rd
    ['J. Minjarez hit by pitch (0-0); RJ Williams advanced to second.', 'Berthiaume popped up to 1b (0-2 KF).', 'O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.']
    

    通过字符串函数(.find())提取标题,然后通过sent_tokenize()分析句子。

    【讨论】:

      【解决方案2】:

      回答

      简介

      好的,这适用于您提出的所有用例,但绝不是完美的。句子中间的句号. 会引起并发症。这使得它变得复杂,因为它们不再是普通的句子终止符,而是代表其他东西,例如首字母。

      代码

      You can see this code in use here

      \h*+(.{2,}?(?:\.|$))(?=(?:\h+[A-Z])|$)
      

      结果

      输入 1

      J. Minjarez hit by pitch (0-0); RJ Williams advanced to second. Berthiaume popped up to 1b (0-2 KF). O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.
      

      输出 1

      J. Minjarez hit by pitch (0-0); RJ Williams advanced to second.
      
      Berthiaume popped up to 1b (0-2 KF).
      
      O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.
      

      输入 2

      EZELL, T. lined out to 2b (2-2 FBBKFFF). HOLST, D. flied out to lf (0-2 FK). GAGAN, T. struck out swinging (1-2 BKKS).
      

      输出 2

      EZELL, T. lined out to 2b (2-2 FBBKFFF).
      
      HOLST, D. flied out to lf (0-2 FK).
      

      GAGAN, T. 三振出局 (1-2 BKKS)。


      输入 3

      Berthiaume reached on a fielding error by ss (0-0). O. Salinas fouled out to 1b (2-1 KBB). Q. Rohrbaugh flied out to cf (2-0 BB). B. Cox fouled out to lf (2-2 KBBKF)
      

      输出 3

      Berthiaume reached on a fielding error by ss (0-0).
      
      O. Salinas fouled out to 1b (2-1 KBB).
      
      Q. Rohrbaugh flied out to cf (2-0 BB).
      

      说明

      正则表达式的工作方式如下:

      • 在零和无限水平空白\h 字符之间尽可能多次匹配而不返回
      • 捕获 2 到无限制的任意字符(换行符除外),但尽可能少,后跟 . 或字符串结尾 $
      • 确保前一个后跟以下之一
        • 一个到无限的水平空白字符,后跟一个大写字母[A-Z]
        • 字符串结尾$

      我使用 .{2,}? 的原因是指定我们要匹配至少 2 个字符(首字母在 . 之前只有 1 个字符,因此在例如 @987654339 的情况下这些将被忽略为句子@)。它使用惰性量词,以便在匹配下一个标记时停止(点\. [或字符串结尾$])


      编辑

      由于python的re模块不支持所有格量​​词(并且根据regex101似乎也不支持\h作为水平空白字符,所以我稍微编辑了正则表达式,如下所示。

      See this code in use here

      \s*(\S.{1,}?(?:\.|$))(?=(?:\s+[A-Z])|$)
      

      【讨论】:

      • @Jan 我完全同意,但根据使用情况,可能适用于 OP。我并不是说这是最好的解决方案,这就是为什么我在第一句话中说这个答案是绝不是[...]完美,但它确实允许 OP 做什么他们正在尝试使用正则表达式。
      • 我非常感谢您的详尽回答,但是出于这个原因,nltk 可能是我想要走的路线。你的回答确实解决了 OP。
      • @RickAhlf 没有难过的感觉,Jan 的回答可能比使用正则表达式更好。谁知道呢,也许这个答案会对其他人有所帮助;)
      • 我相信它会的。它也让我对正则表达式有了更多的了解,非常感谢!
      • @Jan 谢谢,我在帖子中添加了编辑。这现在应该适用于python。我相信\h在python中也不起作用,但无法确认,我已将其改为\s
      【解决方案3】:

      由于每个句子都以当前的球数和击球数结束,当句号在 i 后面有 ) 时,您可以拆分 -.。此外,正则表达式检查句点前的最后一个字母是否为小写,后面的数据是一个空格,然后是一个大写字母(表示常规句子的结尾和新句子的开头):

      import re
      
      strings = ['UT Arlington 1st - Berthiaume reached on a fielding error  by ss (0-0). O. Salinas fouled out to 1b (2-1 KBB). Q. Rohrbaugh flied out to cf (2-0 BB). B. Cox fouled out to lf (2-2 KBBKF)', 'Southeast Mo. State 1st - EZELL, T. lined out to 2b (2-2 FBBKFFF). HOLST, D. flied out to lf (0-2 FK). GAGAN, T. struck out swinging (1-2 BKKS).', 'UT Arlington 3rd - J. Minjarez hit by pitch (0-0); RJ Williams advanced to second. Berthiaume popped up to 1b (0-2 KF). O. Salinas flied out to cf to right center (2-1 KBB); RJ Williams advanced to third.']
      
      new_data = [re.split("(?<!\d)-(?!\d)|(?<=\))\.|(?<=[a-z])\.(?=\s[A-Z])", i) for i in strings]
      
      for plays in new_data:
          print new_data
      

      【讨论】:

      • 这并不总是正确的:O. Salinas 飞到 cf 到右侧中心 (2-1 KBB); RJ 威廉姆斯晋级第三。
      • 这会拆分字符串末尾的计数,因为大写字母表示音高序列。它还将拆分前往密苏里州东南部的航向,但可以对其进行预处理以避免此结果。
      • @RickAhlf 已修复以避免计数分裂。
      猜你喜欢
      • 2017-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多