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

时间:2018-10-01 19:38:28

标签: python string python-3.x list

很抱歉,标题令人困惑,但是在一行之内描述问题有点困难。所以我有一个看起来像这样的列表:

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

我想得到这样的东西:

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

过程: 1.删​​除所有开头和结尾的空字符串(A之前和D之后的字符串)。 2.删除夹在非空字符串(例如B&C和C&D之间的单个)之间的单个空字符串。但是,如果将多于一个的空字符串夹在中间,请将其保留(例如A和B之间的2个)。

有人可以帮我解决这个问题吗?提前非常感谢您!

2 个答案:

答案 0 :(得分:3)

这是一种可能的解决方案。您可以使用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']

答案 1 :(得分: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 @
)