如何在融合其他空字符串的同时删除夹在非空字符串之间的空字符串?

2024-04-24 00:26:22 发布

您现在位置:Python中文网/ 问答频道 /正文

很抱歉标题很混乱,但是用一行字来描述这个问题有点难。所以我有一个列表如下:

['','','','A','','','B','','C','','D','','','']

我想得到这样的东西:

['A','','','B','C','D']

过程: 1删除所有开始和结束的空字符串(A之前和D之后的字符串)。 2删除被非空字符串(如B&C和C&D之间的字符串)夹在中间的单个空字符串。但是,如果有1个以上的空字符串夹在中间,请保留它们(如A和B之间的2个字符串)。你知道吗

有人能帮我解决这个问题吗?事先非常感谢!你知道吗


Tags: 字符串标题列表过程
2条回答

这不是一个在所有情况下都适用的答案,但是如果您能够识别出列表中不存在的字符,则该答案将有效。一般的想法是加入列表、剥离、替换元素的单个运行,然后在元素上拆分:

设置

L = ['', '', '', 'A', '', '', 'B', '', 'C', '', 'D', '', '', '']
import re

re.sub(r'(?<!@)@@(?!@)', r'@', '@'.join(L).strip('@')).split('@')

['A', '', '', 'B', 'C', 'D']

将其包装在函数中并断言el元素有效:

def custom_stripper(L, el):
    """
    Strips empty elements from start/end of a list,
    and removes single empty whitespace runs

    Parameters
         
    L: iterable, required
        The list to modify
    el: str, required
        An element found nowhere in the joined list

    Returns
       -
    A properly formatted list
    """

    assert(el not in ''.join(L))
    rgx = r'(?<!{el}){el}{el}(?!{el})'.format(el=el)

    return re.sub(rgx, el, el.join(L).strip(el)).split(el)

>>> custom_stripper(L, '@')
['A', '', '', 'B', 'C', 'D']
>>> custom_stripper(L, 'A')
                                     -
AssertionError                            Traceback (most recent call last)
<ipython-input-161-7afa6741e503> in <module>()
  > 1 custom_stripper(L, 'A')

<ipython-input-158-606893c3fe1c> in custom_stripper(L, el)
     11     """
     12
 -> 13     assert(el not in ''.join(L))
     14     rgx = r'(?<!{el}){el}{el}(?!{el})'.format(el=el)
     15

AssertionError:

要分解这一点:

>>> '@'.join(L).strip('@')
'A@@@B@@C@@D'

>>> re.sub(r'(?<!@)@@(?!@)', r'@', 'A@@@B@@C@@D')
'A@@@B@C@D'

>>> 'A@@@B@C@D'.split('@')
['A', '', '', 'B', 'C', 'D']

正则表达式解释

替换是关键,因为它允许替换一行中的两个@(表示列表中只存在一个空字符串的位置)。但是,您必须小心不要在另一个运行的@中替换一行中的两个@(例如,如果一行中有两个空字符串)。这里的关键是消极的向前看/向后看。你知道吗

(?<!                     # Negative lookbehind
  @                      # Asserts string *does not* match @
)                        
@@                       # Matches @@
(?!                      # Negative lookahead
  @                      # Asserts string *does not* match @
)

这里有一个可能的解决方案。您可以使用itertools.groupby来标识相同字符串的运行,并计算一行中出现的字符串数:

>>> import itertools
>>> seq = ['','','','A','','','B','','C','','D','','','']
>>> runs = [(c, len(list(g))) for c,g in itertools.groupby(seq)]
>>> runs
[('', 3), ('A', 1), ('', 2), ('B', 1), ('', 1), ('C', 1), ('', 1), ('D', 1), ('', 3)]

然后删除第一个和最后一个元素(如果它们是空字符串):

>>> if runs[0][0] == '': runs = runs[1:]
...
>>> if runs[-1][0] == '': runs = runs[:-1]
...
>>> runs
[('A', 1), ('', 2), ('B', 1), ('', 1), ('C', 1), ('', 1), ('D', 1)]

然后移除由一个空字符串组成的任何内部组:

>>> runs = [(char, count) for char, count in runs if not (char == '' and count == 1)]
>>> runs
[('A', 1), ('', 2), ('B', 1), ('C', 1), ('D', 1)]

然后重新定位到一个单一的名单运行。你知道吗

>>> result = [char for char, count in runs for _ in range(count)]
>>> result
['A', '', '', 'B', 'C', 'D']

相关问题 更多 >