【问题标题】:Creating two lists from string excluding and including strings between brackets从字符串创建两个列表,排除和包括括号之间的字符串
【发布时间】:2019-01-28 21:12:39
【问题描述】:

假设我们有这样一个字符串:

s = u'apple banana lemmon (hahaha) dog cat whale (hehehe) red blue black'

我想创建以下列表:

including = ['hahaha', 'hehehe']
excluding = ['apple banana lemmon (', ') dog cat whale (', ') red blue black']

第一个列表直接使用正则表达式:

including = re.findall('\((.*?)\)',s)

但我无法为其他列表获得类似的东西。你可以帮帮我吗?提前谢谢你!

【问题讨论】:

  • 使用包含列表拆分字符串?
  • re.split('|'.join(including), s)

标签: python list pandas list-comprehension


【解决方案1】:

使用正则表达式

a = re.findall('\)?[^()]*\(?', s)
excluded = a[::2]
included = a[1::2]
print(included, excluded, sep='\n')

['hahaha', 'hehehe', '']
['apple banana lemmon (', ') dog cat whale (', ') red blue black']

注意空字符串

a = re.findall('\)?[^()]*\(?', s)
excluded = [*filter(bool, a[::2])]
included = [*filter(bool, a[1::2])]
print(included, excluded, sep='\n')

['hahaha', 'hehehe']
['apple banana lemmon (', ') dog cat whale (', ') red blue black']

没有正则表达式

from itertools import cycle

def f(s):
  c = cycle('()')
  a = {'(': 1, ')': 0}
  while s:
    d = next(c)
    i = s.find(d)
    if i > -1:
      j = a[d]
      yield d, s[:i + j]
      s = s[i + j:]
    else:
      yield d, s
      break

included = []
excluded = []

for k, v in f(s):
  if k == '(':
    excluded.append(v)
  else:
    included.append(v)

print(included, excluded, sep='\n')

['hahaha', 'hehehe']
['apple banana lemmon (', ') dog cat whale (', ') red blue black']

同样的想法没有覆盖s

from itertools import cycle

def f(s):
  c = cycle('()')
  a = {'(': 1, ')': 0}
  j = 0
  while True:
    d = next(c)
    i = s.find(d, j)
    if i > -1:
      k = a[d]
      yield d, s[j:i + k]
      j = i + k
    else:
      yield d, s[j:]
      break

included = []
excluded = []

for k, v in f(s):
  if k == '(':
    excluded.append(v)
  else:
    included.append(v)

print(included, excluded, sep='\n')

['hahaha', 'hehehe']
['apple banana lemmon (', ') dog cat whale (', ') red blue black']

【讨论】:

  • 这是一个比我更好、更简洁的答案,应该被记录为已接受的答案
  • 如果可以的话,做个小说明:你的正则表达式假设括号的情况是已知数量的,使用小型解析器之类的东西分成两个列表不是更好吗?
【解决方案2】:

您可以使用正向后视和正向前瞻来拆分括号之间的单词:

>>> re.split(r'(?<=\().*?(?=\))', s)
['apple banana lemmon (', ') dog cat whale (', ') red blue black']

【讨论】:

    【解决方案3】:
    excluding = re.split('|'.join(including), s)
    

    对于您知道包含信息不包含特殊字符或正则表达式定义的简单情况。

    如果您不确定是否会出现这种情况:

    re.split('|'.join(map(re.escape, including)), s)
    

    这将转义特殊的正则表达式字符,否则会导致 re.split 函数功能障碍

    【讨论】:

    • 最好使用map(re.escape, including),否则如果你在字符串中有(haha\d+haha),正则表达式会将\d+解释为一个或多个数字而不是文字\d+
    • 这是真的,但我认为它不适用于被问者会使用的案例场景(我认为),因为他似乎是从真实句子中提取括号信息。再说一次,我可能是错的
    • SO Q&A 不仅对最初的提问者有帮助。所以遇到类似问题的人可能需要致电re.escape
    • 他之前有including吗?
    • 是的,它是简单的正则表达式including = re.findall('\((.*?)\)',s)
    猜你喜欢
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多