在字符串列表中查找分隔符/分隔符

2024-04-18 02:46:47 发布

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

我试图在一个文件中找到可能有或没有分隔符的分隔符,这些分隔符是什么-如果有的话-也不知道。你知道吗

到目前为止,我已经编写了以下代码,试图“解决”这个问题:

strings = [
    'cabhb2k4ack_sfdfd~ffrref_lk',
    'iodja_24ed~092oi3jelk_fcjcad',
    'lkn04432m_90osidjlknxc~o_pf'
]

# Process first line
line1 = strings[0]
separators = set()
for sep in set(line1):
    separators.add(( sep, line1.count(sep) ))

# Process all the others
for line in strings:
    for sep,sepcount in separators.copy():
        if line.count(sep) != sepcount: separators.remove( (sep,sepcount) )

print separators

它返回集合:set([('_', 2), ('~', 1)]),这很好-但不幸的是,它不包含文件中分隔符的顺序。事实上,甚至不知道这些分离器的顺序是否一致。你知道吗

分隔符的规则很简单:

  1. 每行必须出现相同的次数
  2. 它们在每一行上必须以相同的顺序出现
  3. 任何非分隔符字符都不能是分隔符字符。你知道吗

请注意,在上面的示例中,“4”被排除在分隔符之外,因为原因1和3在第三个字符串中出现了两次。你知道吗

问题 如何修改此代码以检查规则2是否正确打印分隔符的顺序?你知道吗


Tags: 文件代码infor顺序countlineprocess
2条回答

根据规则1,每个分隔符都有一个从列表的第一行到最后一行的出现次数/行数。你知道吗

我觉得规则3表达得不太好。我认为应该理解为:“在行中的其他字符中,不能找到用作分隔符的每个字符。”。你知道吗

因此,在给定规则1和规则3的情况下,每一个出现次数/行数在两个连续行之间仅变化一次的字符都不能作为分隔符。你知道吗

因此,下面代码的原理是
·首先要创建一个列表sep_n,列出第一行中出现的所有字符及其在第一行中出现的次数,
·然后沿着S行列表进行迭代,并消除列表sep_n中出现次数不相同的每个字符。你知道吗

S = [
    'cabhb2k4ack_sfdfd~ffrref_lk',
    'iodja_24ed~092oi3jelk_fcjcad',
    'lkn04432m_90osidjlknxc~o_pf',
    'hgtr5v_8mgojnb5+87rt~lhiuhfj_n547'
    ]
# 1.They must occur the same number of times per line, 
line0 = S.pop(0)
sep_n = [ (c,line0.count(c)) for c in line0]
print(line0); print(sep_n,'\n')

for line in S:
    sep_n = [x for x in sep_n if line.count(x[0]) == x[1]]
    print(line); print(sep_n,'\n')

S.insert(0, line0)

# 2.They must occur in the same order on each line,
separators_in_order = [x[0] for x in sep_n]
print('separators_in_order : ',separators_in_order)
separators          = ''.join(set(separators_in_order))

for i,line in enumerate(S):
    if [c for c in line if c in separators] != separators_in_order:
        print(i,line)

如果行中的字符有足够的变化(除了分隔符),那么代码中的sep_n长度会随着列表的迭代而迅速减少。你知道吗

是的。你知道吗

指令sep_n = [ (c,line0.count(c)) for c in line0]负责在separators_in_order中获得的最终顺序是列表S第一行中的顺序。你知道吗

但我无法想象一种方法来测试分隔符的顺序是否从一行到另一行保持不变。事实上,在我看来,在迭代过程中不可能进行这样的测试,因为只有在完全执行迭代之后,才能完全知道分隔符列表。你知道吗

这就是为什么必须在获得sep_n的值之后执行辅助控件的原因。它需要再次遍历列表S
问题是,如果“出现次数/行数在两个连续行之间仅变化一次的每个字符都不能成为分隔符,则可能出现非分隔符字符在所有行中出现的次数完全相同的情况,因此不可能在该行上将其检测为非分隔符发生次数的依据。
但由于这样一个非分隔符字符在稳定出现的字符列表中不总是放在同一个位置,所以二次验证是可能的。你知道吗

最后,一个可能存在的极端情况是:一个非分隔符出现在所有行中,出现的次数完全相同,并且放置在行中的分隔符之间,这样即使通过二次验证也无法检测到它;
我不知道怎么破案。。。。你知道吗

结果是

cabhb2k4ack_sfdfd~ffrref_lk
[('c', 2), ('a', 2), ('b', 2), ('h', 1), ('b', 2), ('2', 1), ('k', 3), ('4', 1), ('a', 2), ('c', 2), ('k', 3), ('_', 2), ('s', 1), ('f', 5), ('d', 2), ('f', 5), ('d', 2), ('~', 1), ('f', 5), ('f', 5), ('r', 2), ('r', 2), ('e', 1), ('f', 5), ('_', 2), ('l', 1), ('k', 3)] 

iodja_24ed~092oi3jelk_fcjcad
[('c', 2), ('a', 2), ('4', 1), ('a', 2), ('c', 2), ('_', 2), ('~', 1), ('_', 2), ('l', 1)] 

lkn04432m_90osidjlknxc~o_pf
[('_', 2), ('~', 1), ('_', 2)] 

hgtr5v_8mgojnb5+87rt~lhiuhfj_n547
[('_', 2), ('~', 1), ('_', 2)] 

separators_in_order :  ['_', '~', '_']

S = [
    'cabhb2k4ack_sfd#fd~ffrref_lk',
    'iodja_24ed~092oi#3jelk_fcjcad',
    'lkn04432m_90osi#djlknxc~o_pf',
    'h#gtr5v_8mgojnb5+87rt~lhiuhfj_n547'
    ]

结果是

cabhb2k4ack_sfd#fd~ffrref_lk
[('c', 2), ('a', 2), ('b', 2), ('h', 1), ('b', 2), ('2', 1), ('k', 3), ('4', 1), ('a', 2), ('c', 2), ('k', 3), ('_', 2), ('s', 1), ('f', 5), ('d', 2), ('#', 1), ('f', 5), ('d', 2), ('~', 1), ('f', 5), ('f', 5), ('r', 2), ('r', 2), ('e', 1), ('f', 5), ('_', 2), ('l', 1), ('k', 3)] 

iodja_24ed~092oi#3jelk_fcjcad
[('c', 2), ('a', 2), ('4', 1), ('a', 2), ('c', 2), ('_', 2), ('#', 1), ('~', 1), ('_', 2), ('l', 1)] 

lkn04432m_90osi#djlknxc~o_pf
[('_', 2), ('#', 1), ('~', 1), ('_', 2)] 

h#gtr5v_8mgojnb5+87rt~lhiuhfj_n547
[('_', 2), ('#', 1), ('~', 1), ('_', 2)] 

separators_in_order :  ['_', '#', '~', '_']
1 iodja_24ed~092oi#3jelk_fcjcad
3 h#gtr5v_8mgojnb5+87rt~lhiuhfj_n547

.
. 你知道吗

注1
指令line0 = S.pop(0)完成
为了避免指令for line in S[1:]:关闭,
因为S[1:]创建了一个新的列表,这个列表可能很重。你知道吗

是的。你知道吗

注2
为了避免在S中每次迭代时创建新的sep_n列表,
最好按以下方式编写迭代:

for line in S:
    for x in sep_n:
        if line.count(x[0]) == x[1]:
            sep_n = [x for x in sep_n if line.count(x[0]) == x[1]]
            break
    print(line); print(sep_n,'\n')

我会使用Counter而不是.count,接受skrrgwasme的建议使用列表,并使用itertools.combinations来帮助迭代可能的分隔符子集:

from collections import Counter
from itertools import combinations

def subsets(elems):
    for width in range(1, len(elems)+1):
        for comb in combinations(elems, width):
            yield comb

def sep_order(string, chars):
    chars = set(chars)
    order = tuple(c for c in string if c in chars)
    return order

def find_viable_separators(strings):
    counts = [Counter(s) for s in strings]
    chars = {c for c in counts[0]
             if all(count[c]==counts[0][c] for count in counts)}
    for seps in subsets(chars):
        orders = {sep_order(s, seps) for s in strings}
        if len(orders) == 1:
            yield seps, next(iter(orders))

这让我

>>> 
... strings = [
...     'cabhb2k4ack_sfdfd~ffrref_lk',
...     'iodja_24ed~092oi3jelk_fcjcad',
...     'lkn04432m_90osidjlknxc~o_pf'
... ]
... 
... for seps, order in find_viable_separators(strings):
...     print("possible separators:", seps, "with order:", order)
...             
possible separators: ('~',) with order: ('~',)
possible separators: ('_',) with order: ('_', '_')
possible separators: ('~', '_') with order: ('_', '~', '_')

相关问题 更多 >