【问题标题】:how to find a continuous string using python如何使用python查找连续字符串
【发布时间】:2018-05-09 14:33:53
【问题描述】:

给定一个字符串(例如,jaghiuuabc),我想在字母表中找到一个带有后续字母的字符串

这是我的代码

import string
alpha = list(string.ascii_lowercase)

s = 'jaghiuuabc'

a = []
for i in range(len(alpha)-1):
    for j in range(len(s)-1)
      if s[j] in alpha[i]:
         a.append(s[j])

print(a)

【问题讨论】:

  • 你的意思是要找到字母表中字母都相邻的字符串的一部分吗?
  • 我认为 OP 想要的只是从字符串中删除非字母字符
  • 您的意思是您希望该数据的输出为'ghiabc'?或者['ghi', 'abc']
  • 一个列表。谢谢!

标签: python python-3.x for-loop


【解决方案1】:

这可以用纯 Python 轻松完成

Python 3(也应该与 Python 2 一起使用)实现。一个简单的 8 班轮

s = 'jaghiuuabc'

prev, counter, dct = None, 0, dict()
for i in s:
    if prev is not None:
        if not chr(ord(prev) + 1) == i:
            counter += 1
    prev = i
    dct.setdefault(counter, []).append(prev)

[''.join(dct[d]) for d in dct if len(dct[d]) > 1]

Out[51]: ['ghi', 'abc']

ord 将 char 转换为等效的 ASCII 数字

chr 将数字转换为等效的 ASCII 字符

setdefault 如果键不存在,则将默认值设置为列表

【讨论】:

  • 不错。 :) 我自己经常使用dct.setdefault(key, []).append(value),但我们这里并不需要dict,因为保证键是有序的,所以我们可以使用列表。通过稍微改变逻辑,我们可以将 if 测试的数量减少到 1 个。请参阅我的答案末尾以了解您的代码的变体。
【解决方案2】:

如果没有任何外部模块的递归呢?

a='jaghiuuabc'


import string
alpha = list(string.ascii_lowercase)
def trech(string_1,chr_list,new_string):
    final_list=[]
    if not string_1:
        return 0
    else:

        for chunk in range(0,len(string_1),chr_list):
            for sub_chunk in range(2,len(string_1)+1):
                if string_1[chunk:chunk + sub_chunk] in ["".join(alpha[i:i + sub_chunk]) for i in range(0, len(alpha), 1)]:
                    final_list.append(string_1[chunk:chunk + sub_chunk])

    if final_list:
        print(final_list)

    return trech(string_1[1:],chr_list-1,new_string)

print(trech(a,len(a),alpha))

输出:

['gh', 'ghi']
['hi']
['ab', 'abc']
['bc']
0

【讨论】:

    【解决方案3】:

    Python 2.6 itertools docs 中有一个很好的示例,它展示了如何查找连续序列。引用:

    使用groupby 查找连续数字的运行。的关键 解决方案与一个范围不同,因此连续的数字都是 出现在同一组中。

    由于某些奇怪的原因,该示例不在文档的更高版本中。该代码适用于数字序列,下面的代码显示了如何使其适用于字母。

    from itertools import groupby
    
    s = 'jaghiuuabc'
    
    def keyfunc(t):
        ''' Subtract the character's index in the string 
            from its Unicode codepoint number. 
        ''' 
        i, c = t
        return ord(c) - i
    
    a = []
    for k, g in groupby(enumerate(s), key=keyfunc):
        # Extract the chars from the (index, char) tuples in the group
        seq = [t[1] for t in g]
        if len(seq) > 1:
            a.append(''.join(seq))
    
    print(a)
    

    输出

    ['ghi', 'abc']
    

    工作原理

    这段代码的核心是

    groupby(enumerate(s), key=keyfunc)
    

    enumerate(s)s 中的每个字符生成包含索引号和字符的元组。例如:

    s = 'ABCEF'
    for t in enumerate(s):
        print(t)
    

    输出

    (0, 'A')
    (1, 'B')
    (2, 'C')
    (3, 'E')
    (4, 'F')
    

    groupby 从序列或迭代器中获取项目,并将相邻的相等项目聚集到组中。默认情况下,它只是比较项目的值以查看它们是否相等。但你也可以给它一个关键的功能。当您这样做时,它会将每个项目传递给 key 函数,并使用该 key 函数返回的结果进行相等性测试。

    这是一个简单的例子。首先,我们定义了一个函数div_by_10,它使用整数除法将一个数字除以10。这基本上摆脱了数字中的最后一位。

    def div_by_10(n):
        return n // 10
    
    a = [2, 5, 10, 13, 17, 21, 22, 29, 33, 35]
    b = [div_by_10(u) for u in a]
    print(a)
    print(b)
    

    输出

    [2, 5, 10, 13, 17, 21, 22, 29, 33, 35]
    [0, 0, 1, 1, 1, 2, 2, 2, 3, 3]
    

    因此,如果我们使用div_by_10 作为groupby 的键函数,它将忽略每个数字中的最后一个数字,因此如果它们仅在最后一个数字上不同,它将把相邻的数字组合在一起。

    from itertools import groupby
    
    def div_by_10(n):
        return n // 10
    
    a = [2, 5, 10, 13, 17, 21, 22, 29, 33, 35]
    print(a)
    for key, group in groupby(a, key=div_by_10):
        print(key, list(group))        
    

    输出

    [2, 5, 10, 13, 17, 21, 22, 29, 33, 35]
    0 [2, 5]
    1 [10, 13, 17]
    2 [21, 22, 29]
    3 [33, 35]
    

    我的keyfunc 接收一个 (index_number, character) 元组并从字符的代码号中减去该 index_number 并返回结果。让我们看看我之前的 'ABCEF' 示例有什么作用:

    def keyfunc(t):
        i, c = t
        return ord(c) - i
    
    for t in enumerate('ABCEF'):
        print(t, keyfunc(t))
    

    输出

    (0, 'A') 65
    (1, 'B') 65
    (2, 'C') 65
    (3, 'E') 66
    (4, 'F') 66
    

    'A' 的代号是 65,'B' 的代号是 66,'C' 的代号是 67,等等。所以当我们从每个 'A' 的代号中减去索引时'、'B' 和 'C' 我们得到 65。但是我们跳过了 'D',所以当我们对 'E' 和 'F' 进行减法时,我们得到 66。这就是 groupby 可以输入 'A' 的方式、“B”和“C”在一组中,“E”和“F”在下一组中。

    这可能是个棘手的问题。不要指望一下子就能完全理解。但如果你自己做一些实验,我相信它会逐渐深入。;)


    只是为了好玩,这里是该代码的不可读的多重嵌套列表理解版本。 ;)

    print([z for _, g in groupby(enumerate(s),lambda t:ord(t[1])-t[0])for z in[''.join([*zip(*g)][1])]if len(z)>1])
    

    这是另一个受Amit Tripathi's answer 启发的版本。这个不使用任何导入,因为它手动进行分组。 prev 包含前一个字符的代码点编号。我们将prev 初始化为-2,以便第一次执行if i != prev + 1 测试时保证为真,因为ord(ch) 的最小可能值为零,因此将向groups 添加一个新的空列表。

    s = 'jaghiuuabcxyzq'
    
    prev, groups = -2, []
    for ch in s:
        i = ord(ch)
        if i != prev + 1:
            groups.append([])
        groups[-1].append(ch)
        prev = i
    
    print(groups)
    a = [''.join(u) for u in groups if len(u) > 1]
    print(a)
    

    输出

    [['j'], ['a'], ['g', 'h', 'i'], ['u'], ['u'], ['a', 'b', 'c'], ['x', 'y', 'z'], ['q']]
    ['ghi', 'abc', 'xyz']
    

    【讨论】:

    • @JoydeepRoychowdhury 我会为我的答案添加更多解释。我承认如果您不熟悉itertools.groupby,可能不容易理解我的代码;你还需要知道enumerate 做了什么。有一些很好的groupby 例子here
    • @JoydeepRoychowdhury 请查看我的更新答案。我希望它能让我们更容易理解发生了什么。
    • 现在我知道 enumerate 和 groupby 做了什么,再次感谢
    • 嗨 - @PM 2Ring,你能建议我类似的问题吗?
    • @PM2Ring 感谢您的提及。我会很感激编辑我的答案而不是它:)
    猜你喜欢
    • 2020-03-20
    • 2021-07-10
    • 2019-12-13
    • 2011-11-01
    • 1970-01-01
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多