如何判断字符串是否在Python中重复?


352

我正在寻找一种方法来测试给定的字符串是否对整个字符串重复。

例子:

[
    '0045662100456621004566210045662100456621',             # '00456621'
    '0072992700729927007299270072992700729927',             # '00729927'
    '001443001443001443001443001443001443001443',           # '001443'
    '037037037037037037037037037037037037037037037',        # '037'
    '047619047619047619047619047619047619047619',           # '047619'
    '002457002457002457002457002457002457002457',           # '002457'
    '001221001221001221001221001221001221001221',           # '001221'
    '001230012300123001230012300123001230012300123',        # '00123'
    '0013947001394700139470013947001394700139470013947',    # '0013947'
    '001001001001001001001001001001001001001001001001001',  # '001'
    '001406469760900140646976090014064697609',              # '0014064697609'
]

是重复的字符串,并且

[
    '004608294930875576036866359447',
    '00469483568075117370892018779342723',
    '004739336492890995260663507109',
    '001508295625942684766214177978883861236802413273',
    '007518796992481203',
    '0071942446043165467625899280575539568345323741',
    '0434782608695652173913',
    '0344827586206896551724137931',
    '002481389578163771712158808933',
    '002932551319648093841642228739',
    '0035587188612099644128113879',
    '003484320557491289198606271777',
    '00115074798619102416570771',
]

是那些没有的例子。

我得到的字符串的重复部分可能会很长,并且字符串本身可以是500个或更多字符,因此循环遍历每个字符以尝试构建模式,然后检查模式与字符串的其余部分似乎很慢。将其乘以可能的数百个字符串,就看不到任何直观的解决方案。

我对正则表达式进行了一些研究,当您知道要查找的内容时,或者至少在寻找所需模式的长度时,它们似乎非常有用。不幸的是,我都不知道。

我怎么知道一个字符串是否在重复本身,如果是,最短的重复子序列是什么?


15
循环遍历每个试图建立模式的字符,然后检查模式与字符串的其余部分,这似乎很慢 -但这是吗?
蒂姆(Tim)


2
@AvinashRaj仅匹配字符串的一部分,而不是完整的部分。
约翰

11
@AvinashRaj OP正在询问所有可能的解决方案。您链接到的问题仅接受正则表达式解决方案。请注意,正则表达式也许能解决这个问题,但在很多比需要更多的时间。例如,最佳解决方案(即线性时间)将使用文本的后缀树。您只需要找到最长的重复子字符串,然后对长度进行一些检查即可。
Bakuriu 2015年

2
@ TigerhawkT3实际的数据集太大而笨拙,但是问题中的示例是其中的一部分,如果您愿意,这里还有更多内容
约翰

Answers:


570

这是一个简洁的解决方案,它避免了正则表达式和缓慢的Python内循环:

def principal_period(s):
    i = (s+s).find(s, 1, -1)
    return None if i == -1 else s[:i]

有关基准测试结果,请参阅由@davidism发起的Community Wiki答案。综上所述,

David Zhang的解决方案无疑是赢家,对于大型示例集,其性能至少比其他同类产品高出5倍。

(那个答案的话,不是我的。)

这是基于这样的观察,即且仅当字符串等于其自身的非平凡旋转时,它才是周期性的。@AleksiTorhamo的荣誉,意识到我们可以从sin 的第一次出现的索引中恢复本金周期(s+s)[1:-1],并告知我Python的可选参数start和自end变量string.find


19
您可以使用.find().index()代替它来扩展它以找到最短的重复子序列in(s+s).find(s, 1, -1)
Aleksi Torhamo 2015年

11
另外,我认为这(s+s).find(s, 1, -1)将(非常稍微)快于(s+s)[1:-1].find(s),至少对于较大的字符串而言,因为切片意味着您必须创建(几乎)整个字符串的另一个副本。
Aleksi Torhamo 2015年

13
就像您从周期函数中获取正弦波或余弦波并将其向右移动一样。由于它是完全周期性的,因此波最终将完美匹配...与该解决方案的数学相似之处是惊人的。:)我希望我能给你+∞投票。
沙申克2015年

6
Guido 对PEP 8最新更新与此处相关:“在返回语句中保持一致。函数中的所有return语句都应返回表达式,或者都不返回如果任何return语句返回表达式,则不包含任何值的任何return语句。return应该将其显式声明为return None,并且在函数的末尾(如果可以到达)应该存在显式的return语句。”
零比雷埃夫斯2015年

8
@WayneConrad一个字符串,比如"abcd",爆开右边的人物,并坚持它放回到左边来获得"dabc"。此过程称为将字符串向右旋转1个字符。重复n次数以n字符向右旋转字符串。现在观察,如果我们有一个字符串,k向右旋转任意倍数,k则字符串保持不变。一个平凡的字符串的转动是一个其字符数不是字符串的长度的倍数。
张大卫2015年

181

这是使用正则表达式的解决方案。

import re

REPEATER = re.compile(r"(.+?)\1+$")

def repeated(s):
    match = REPEATER.match(s)
    return match.group(1) if match else None

迭代问题中的示例:

examples = [
    '0045662100456621004566210045662100456621',
    '0072992700729927007299270072992700729927',
    '001443001443001443001443001443001443001443',
    '037037037037037037037037037037037037037037037',
    '047619047619047619047619047619047619047619',
    '002457002457002457002457002457002457002457',
    '001221001221001221001221001221001221001221',
    '001230012300123001230012300123001230012300123',
    '0013947001394700139470013947001394700139470013947',
    '001001001001001001001001001001001001001001001001001',
    '001406469760900140646976090014064697609',
    '004608294930875576036866359447',
    '00469483568075117370892018779342723',
    '004739336492890995260663507109',
    '001508295625942684766214177978883861236802413273',
    '007518796992481203',
    '0071942446043165467625899280575539568345323741',
    '0434782608695652173913',
    '0344827586206896551724137931',
    '002481389578163771712158808933',
    '002932551319648093841642228739',
    '0035587188612099644128113879',
    '003484320557491289198606271777',
    '00115074798619102416570771',
]

for e in examples:
    sub = repeated(e)
    if sub:
        print("%r: %r" % (e, sub))
    else:
        print("%r does not repeat." % e)

...产生以下输出:

'0045662100456621004566210045662100456621': '00456621'
'0072992700729927007299270072992700729927': '00729927'
'001443001443001443001443001443001443001443': '001443'
'037037037037037037037037037037037037037037037': '037'
'047619047619047619047619047619047619047619': '047619'
'002457002457002457002457002457002457002457': '002457'
'001221001221001221001221001221001221001221': '001221'
'001230012300123001230012300123001230012300123': '00123'
'0013947001394700139470013947001394700139470013947': '0013947'
'001001001001001001001001001001001001001001001001001': '001'
'001406469760900140646976090014064697609': '0014064697609'
'004608294930875576036866359447' does not repeat.
'00469483568075117370892018779342723' does not repeat.
'004739336492890995260663507109' does not repeat.
'001508295625942684766214177978883861236802413273' does not repeat.
'007518796992481203' does not repeat.
'0071942446043165467625899280575539568345323741' does not repeat.
'0434782608695652173913' does not repeat.
'0344827586206896551724137931' does not repeat.
'002481389578163771712158808933' does not repeat.
'002932551319648093841642228739' does not repeat.
'0035587188612099644128113879' does not repeat.
'003484320557491289198606271777' does not repeat.
'00115074798619102416570771' does not repeat.

正则表达式(.+?)\1+$分为三个部分:

  1. (.+?)是一个匹配组,其中包含至少一个(但尽可能少)任何字符(因为+?不是贪婪)。

  2. \1+ 在第一部分中检查匹配组的至少一个重复。

  3. $检查字符串的结尾,以确保在重复的子字符串之后没有多余的,非重复的内容(并使用re.match()确保在重复的子字符串之前没有非重复的文本)。

在Python 3.4和更高版本中,您可以删除$re.fullmatch()来代替,或者(在任何Python中至少可以追溯到2.3)使用另一种方式并re.search()与regex一起使用^(.+?)\1+$,所有这些都比其他人更受个人喜好。


6
我不知道为什么这两个简洁的答案不是投票最高的答案。其他答案也不错,但是这个答案要好得多。(它可能使用经常被修饰的正则表达式,但是我可以比其他更长的答案更容易地检查它,这些答案充满了嵌套的块,潜在的错别字,错位错误等。)我想。
Paul Draper 2015年

9
我认为有两个主要原因:1)一些程序员更喜欢数学而不是正则表达式; 2)由于改变输入字符串的长度和性质使性能(超长边沿大小字符串)的答案不同。 (甚至可能不会出现在实际数据中)使该解决方案显得次优。
TigerhawkT3 2015年

有时您会遇到对正则表达式的偏见。Ive有2位经理禁止使用正则表达式,因为他们听说正则表达式是该工作的错误工具。除课程外,他们继续要求我实施一个正则表达式引擎
joojaa 2015年

1
@PaulDraper:猜猜正则表达式在后台做什么?它解析字符串并存储每个元素,直到可能的重复匹配发生。那与OP状态太慢一样。仅仅因为它是2班轮,就没有任何性能上的胜利。
dhein 2015年

2
@Zaibis,我通常会同意,但这既是最短也是最快的解决方案(stackoverflow.com/a/29482936/1212596) ...。除了David's,它是在我发表评论后发布的。实际上,我更喜欢David的方法(聪明!)。
Paul Draper 2015年

90

您可以观察到对于要考虑重复的字符串,必须将其长度除以重复序列的长度。鉴于此,这是一个生成长度为从1n / 2包括的长度的除数的解决方案,将原始字符串分成具有除数长度的子字符串,并测试结果集的相等性:

from math import sqrt, floor

def divquot(n):
    if n > 1:
        yield 1, n
    swapped = []
    for d in range(2, int(floor(sqrt(n))) + 1):
        q, r = divmod(n, d)
        if r == 0:
            yield d, q
            swapped.append((q, d))
    while swapped:
        yield swapped.pop()

def repeats(s):
    n = len(s)
    for d, q in divquot(n):
        sl = s[0:d]
        if sl * q == s:
            return sl
    return None

编辑:在Python 3中,/运算符已更改为默认情况下进行浮点除法。要从intPython 2中进行除法,可以改用//运算符。感谢@ TigerhawkT3引起我的注意。

//运算符在Python 2和Python 3中都执行整数除法,因此我更新了答案以支持这两个版本。现在,我们测试以查看所有子串是否相等的部分是使用all和生成器表达式的短路操作。

更新:为响应原始问题的更改,现在对代码进行了更新,以返回最小的重复子字符串(如果存在),None如果不存在,则返回最小。@godlygeek建议使用divmod减少divisors生成器上的迭代次数,并且代码也已更新为与此匹配。现在,它n以升序返回所有正数除数,不包括n其本身。

进一步更新以提高性能:经过多次测试,我得出的结论是,简单地测试字符串相等性具有Python中任何切片或迭代器解决方案中最好的性能。因此,我从@ TigerhawkT3的书中抽出了叶子,并更新了我的解决方案。现在它的速度是以前的6倍,比Tigerhawk的解决方案快得多,但比David的解决方案慢。


3
这个解决方案是惊人的。您可以更改除数方法以遵循生产消费模式。这样一来,它们就可以找到结果。如果这不是最高答案,那将是一个耻辱。其他一切都是蛮力。
JustinDanielson

3
@JustinDanielson它返回从生成器表达式创建的生成器对象,该生成器表达式是隐式生成器:)它将对除数进行延迟求值。
Shashank 2015年

1
哦 我不知道 好吧,那就更好了。:DI了解为什么要避免sqrt,但是您可以使用n / 2作为除数范围的上限。
JustinDanielson

1
@JustinDanielson感谢您的建议,现在范围上限已(n/2)包含在内。
沙善

1
n / 2divisors()n // 2
TigerhawkT3 2015年

87

以下是针对此问题的各种答案的一些基准。有一些令人惊讶的结果,包括不同的性能,具体取决于所测试的字符串。

修改了某些功能以使其与Python 3兼容(主要是通过替换///以确保整数除法)。如果发现错误,请添加功能或添加另一个测试字符串,请在Python聊天室中 ping @ZeroPiraeus 。

总结:对于此处由OP提供的大量示例数据,最佳和最差解决方案之间存在大约50倍的差异(通过评论)。David Zhang的解决方案无疑是赢家,对于大型示例集,其解决方案比其他所有解决方案都高出约5倍。

在极大的“不匹配”情况下,几个答案非常慢。否则,根据测试,功能似乎是相等的,或者是明显的赢家。

以下是结果,包括使用matplotlib和seaborn绘制的图以显示不同的分布:


语料库1(提供的示例-小集)

mean performance:
 0.0003  david_zhang
 0.0009  zero
 0.0013  antti
 0.0013  tigerhawk_2
 0.0015  carpetpython
 0.0029  tigerhawk_1
 0.0031  davidism
 0.0035  saksham
 0.0046  shashank
 0.0052  riad
 0.0056  piotr

median performance:
 0.0003  david_zhang
 0.0008  zero
 0.0013  antti
 0.0013  tigerhawk_2
 0.0014  carpetpython
 0.0027  tigerhawk_1
 0.0031  davidism
 0.0038  saksham
 0.0044  shashank
 0.0054  riad
 0.0058  piotr

语料库1图


语料库2(提供的示例-大集合)

mean performance:
 0.0006  david_zhang
 0.0036  tigerhawk_2
 0.0036  antti
 0.0037  zero
 0.0039  carpetpython
 0.0052  shashank
 0.0056  piotr
 0.0066  davidism
 0.0120  tigerhawk_1
 0.0177  riad
 0.0283  saksham

median performance:
 0.0004  david_zhang
 0.0018  zero
 0.0022  tigerhawk_2
 0.0022  antti
 0.0024  carpetpython
 0.0043  davidism
 0.0049  shashank
 0.0055  piotr
 0.0061  tigerhawk_1
 0.0077  riad
 0.0109  saksham

语料库1图


语料库3(边缘案例)

mean performance:
 0.0123  shashank
 0.0375  david_zhang
 0.0376  piotr
 0.0394  carpetpython
 0.0479  antti
 0.0488  tigerhawk_2
 0.2269  tigerhawk_1
 0.2336  davidism
 0.7239  saksham
 3.6265  zero
 6.0111  riad

median performance:
 0.0107  tigerhawk_2
 0.0108  antti
 0.0109  carpetpython
 0.0135  david_zhang
 0.0137  tigerhawk_1
 0.0150  shashank
 0.0229  saksham
 0.0255  piotr
 0.0721  davidism
 0.1080  zero
 1.8539  riad

语料库3图


在此处获得测试和原始结果。


37

非正则表达式解决方案:

def repeat(string):
    for i in range(1, len(string)//2+1):
        if not len(string)%len(string[0:i]) and string[0:i]*(len(string)//len(string[0:i])) == string:
            return string[0:i]

更快的非正则表达式解决方案,这要感谢@ThatWeirdo(请参见评论):

def repeat(string):
    l = len(string)
    for i in range(1, len(string)//2+1):
        if l%i: continue
        s = string[0:i]
        if s*(l//i) == string:
            return s

上面的解决方案很少比原始解决方案慢几个百分点,但通常会快很多-有时快很多。对于较长的字符串,它仍然不比davidism的快,而对于短字符串,zero的正则表达式解决方案更胜一筹。它以大约1000-1500个字符的字符串显示出来,速度最快(根据github上davidism的测试-请参见他的回答)。无论如何,在我测试的所有情况下,它都是第二快的(或更好的)。谢谢,ThatWeirdo。

测试:

print(repeat('009009009'))
print(repeat('254725472547'))
print(repeat('abcdeabcdeabcdeabcde'))
print(repeat('abcdefg'))
print(repeat('09099099909999'))
print(repeat('02589675192'))

结果:

009
2547
abcde
None
None
None

这不是强力解决方案吗?
JustinDanielson

7
@JustinDanielson是的。但是仍然有解决方案。
Sinkingpoint 2015年

3
对于短字符串,我看到大约1e-5到3e-5秒,对于成功的长字符串(1000个字符),大约3e-5至4e-5秒,对于不成功的长字符串(最坏的情况),则不到一毫秒。因此,一千个1000个字符的字符串大约需要一秒钟。与数学答案相比,这会发现匹配速度快10倍,但失败时间要长3倍。
TigerhawkT3 2015年

repeat('aa')返回None
Tom Cornebize

2
len(string[0:i])始终等于i(至少在这种情况下)。替换这些变量,并保存len(string)string[0:i]变量可能会加快处理速度。也是IMO,这是一个很棒的解决方案,太棒了;)
ThatWeirdo 2015年

24

首先,将字符串减半,只要它是“ 2部分”重复项即可。如果重复数为偶数,则会减少搜索空间。然后,继续寻找最小的重复字符串,检查是否通过将越来越大的子字符串拆分成完整的字符串而只得到空值。仅length // 2需要测试最多的子字符串,因为任何重复的内容都不会重复。

def shortest_repeat(orig_value):
    if not orig_value:
        return None

    value = orig_value

    while True:
        len_half = len(value) // 2
        first_half = value[:len_half]

        if first_half != value[len_half:]:
            break

        value = first_half

    len_value = len(value)
    split = value.split

    for i in (i for i in range(1, len_value // 2) if len_value % i == 0):
        if not any(split(value[:i])):
            return value[:i]

    return value if value != orig_value else None

这将返回最短匹配项,如果没有匹配项,则返回None。


16

O(n)在最坏的情况下,也可以使用前缀功能解决该问题。

请注意,这可能是在一般的情况下慢(UPD:是慢得多),比取决于除数的一些其他的解决方案n,我认为不好的情况下,他们一会,但通常会发现失败越早aaa....aab,那里n - 1 = 2 * 3 * 5 * 7 ... *p_n - 1 a

首先需要计算前缀函数

def prefix_function(s):
    n = len(s)
    pi = [0] * n
    for i in xrange(1, n):
        j = pi[i - 1]
        while(j > 0 and s[i] != s[j]):
            j = pi[j - 1]
        if (s[i] == s[j]):
            j += 1
        pi[i] = j;
    return pi

那么要么没有答案,要么最短的时间是

k = len(s) - prefix_function(s[-1])

并且您只需要检查是否k != n and n % k == 0(如果k != n and n % k == 0答案为s[:k],则没有答案

您可以在此处检查证明(俄语,但在线翻译可能会解决问题)

def riad(s):
    n = len(s)
    pi = [0] * n
    for i in xrange(1, n):
        j = pi[i - 1]
        while(j > 0 and s[i] != s[j]):
            j = pi[j - 1]
        if (s[i] == s[j]):
            j += 1
        pi[i] = j;
    k = n - pi[-1]
    return s[:k] if (n != k and n % k == 0) else None

您的prefix_function()Python是无效的:您的whileif语句中缺少冒号,而&&不是and。修复这些问题后,UnboundLocalError: local variable 'i' referenced before assignment由于line ,它失败for i in range(i, n):
零比雷埃夫斯2015年

谢谢:-)如果您可以组合一个函数,该函数使用您的函数prefix_function()返回与其他答案相似的结果-最短的子字符串或None-我将把它包含在我组合在一起的修订基准中。
零比雷埃夫斯2015年

@ZeroPiraeus,实际上工作正常,我只是用一种错误的方式称呼它
RiaD

16

这个版本只尝试那些影响字符串长度的候选序列长度。并使用*运算符从候选序列中构建一个全长字符串:

def get_shortest_repeat(string):
    length = len(string)
    for i in range(1, length // 2 + 1):
        if length % i:  # skip non-factors early
            continue

        candidate = string[:i]
        if string == candidate * (length // i):
            return candidate

    return None

感谢TigerhawkT3注意到,length // 2如果不+ 1这样做,将无法匹配abab案件。


实际上,该解决方案与我的优化解决方案完全相同。我看到您的range限制为length//2,就像我一样- length//2+1如果要捕获完全加倍的字符串(例如'aabaab'),则必须将其更改为。
TigerhawkT3 2015年

现在它们是相同的!\ o /以后我需要更多地关注优化,但是我很高兴算法本身是合理的。
TigerhawkT3 2015年

15

这是没有正则表达式的直接解决方案。

对于s从零索引开始的,长度为1到的len(s)子字符串,请检查该子字符串substr是否为重复模式。可以通过将substr其自身的ratio时间串联在一起来执行此检查,以使由此形成的字符串的长度等于的长度s。因此ratio=len(s)/len(substr)

当找到第一个这样的子字符串时返回。如果存在,这将提供最小的子字符串。

def check_repeat(s):
    for i in range(1, len(s)):
        substr = s[:i]
        ratio = len(s)/len(substr)
        if substr * ratio == s:
            print 'Repeating on "%s"' % substr
            return
    print 'Non repeating'

>>> check_repeat('254725472547')
Repeating on "2547"
>>> check_repeat('abcdeabcdeabcdeabcde')
Repeating on "abcde"

现在,我仔细地看了一下,似乎与我最初发布的(在进行任何编辑之前)解决方案几乎相同,唯一的区别是节省了长度和子字符串。我想我有一个很好的算法。:P
TigerhawkT3 2015年

@ TigerhawkT3是的,的确如此!:)
Saksham Varma 2015年

9

我从八个以上的解决方案开始。一些基于正则表达式(match,findall,split),一些基于字符串切片和测试,而另一些基于字符串方法(find,count,split)。每种代码在代码清晰度,代码大小,速度和内存消耗方面都有好处。当我注意到执行速度被列为重要事项时,我将在此处发布答案,因此我进行了更多测试和改进以得出结论:

def repeating(s):
    size = len(s)
    incr = size % 2 + 1
    for n in xrange(1, size//2+1, incr):
        if size % n == 0:
            if s[:n] * (size//n) == s:
                return s[:n]

该答案似乎与此处的其他一些答案相似,但是它具有一些其他人未使用的速度优化:

  • xrange 在这个应用程序中速度更快,
  • 如果输入字符串是奇数长度,请不要检查任何偶数长度的子字符串,
  • 通过s[:n]直接使用,我们避免在每个循环中创建变量。

我很想看看它在常见硬件的标准测试中如何执行。我相信,在大多数测试中,这将远远超出David Zhang的出色算法,但否则应该很快。

我发现这个问题非常违反直觉。我认为很快的解决方案很慢。看起来很慢的解决方案很快!看起来,使用乘法运算符和字符串比较对Python的字符串创建进行了高度优化。


一点也不差劲:-)该基准测试在Python 3.4上运行(部分是因为OP没有指定版本,这是每个人都应该使用的版本,部分是因为它使用了新statistics模块),所以我不得不将/s 更改为//s并替换xrange()range()(其行为类似于xrange()3.x中的2.x )。
零比雷埃夫斯2015年

这是基准测试的修订版,因此您可以查看我的更改。
零比雷埃夫斯2015年

谢谢零。那太快了。结果略低于我的预测。我怀疑我在Python 2.7中用于速度的技术在Python 3.4中不是很有效。哦,很好-一个有趣的教育性练习。
逻辑骑士

//3.x中的是整数除法(就像的2.x行为一样/),而3.x的/是浮点除法(我敢肯定这会慢得多,即使它没有导致尝试使用的方法破坏了您的解决方案)浮点数作为索引)。如前所述,3.x range()与2.x相同xrange()range()3.x中不存在等同于2.x的版本。因此,我认为这并不是基准测试与您设定的任何时间差异的原因。可能是3.x总体上比2.x慢(或者您的机器比我的机器快)。
零比雷埃夫斯2015年

当我得到了一段时间,我得仔细看的Python 2和Python 3之间的运行时间差
逻辑骑士

2

此功能运行非常快(经过测试,在超过10万个字符的字符串上,此功能比最快的解决方案快3倍以上,并且重复模式越长,差异越大)。它试图最小化获得答案所需的比较次数:

def repeats(string):
    n = len(string)
    tried = set([])
    best = None
    nums = [i for i in  xrange(2, int(n**0.5) + 1) if n % i == 0]
    nums = [n/i for i in nums if n/i!=i] + list(reversed(nums)) + [1]
    for s in nums:
        if all(t%s for t in tried):
            print 'Trying repeating string of length:', s
            if string[:s]*(n/s)==string:
                best = s
            else:
                tried.add(s)
    if best:
        return string[:best]

请注意,例如对于长度为8的字符串,它仅检查大小为4的片段,并且不必进一步测试,因为长度为1或2的模式将导致重复长度为4的模式:

>>> repeats('12345678')
Trying repeating string of length: 4
None

# for this one we need only 2 checks 
>>> repeats('1234567812345678')
Trying repeating string of length: 8
Trying repeating string of length: 4
'12345678'

谢谢:)我并没有对其进行太多优化。我只是想提出一种不同的方法,因为其他答案都集中在寻找模式上,而我的方法集中在证明没有模式上:)因此,对于随机字符串,我的算法应该运行得更快。
Piotr Dabkowski

0

在David Zhang的回答中,如果我们有某种循环缓冲区,这将不起作用:principal_period('6210045662100456621004566210045662100456621')由于开始的原因621,我希望将其吐出:00456621

扩展他的解决方案,我们可以使用以下方法:

def principal_period(s):
    for j in range(int(len(s)/2)):
        idx = (s[j:]+s[j:]).find(s[j:], 1, -1)
        if idx != -1:
            # Make sure that the first substring is part of pattern
            if s[:j] == s[j:][:idx][-j:]:
                break

    return None if idx == -1 else s[j:][:idx]

principal_period('6210045662100456621004566210045662100456621')
>>> '00456621'

-1

这是python中的代码,用于检查用户给定的主字符串中子字符串的重复

print "Enter a string...."
#mainstring = String given by user
mainstring=raw_input(">")
if(mainstring==''):
    print "Invalid string"
    exit()
#charlist = Character list of mainstring
charlist=list(mainstring)
strarr=''
print "Length of your string :",len(mainstring)
for i in range(0,len(mainstring)):
    strarr=strarr+charlist[i]
    splitlist=mainstring.split(strarr)
    count = 0
    for j in splitlist:
        if j =='':
            count+=1
    if count == len(splitlist):
        break
if count == len(splitlist):
    if count == 2:
        print "No repeating Sub-String found in string %r"%(mainstring)

    else:
        print "Sub-String %r repeats in string %r"%(strarr,mainstring)
else :
    print "No repeating Sub-String found in string %r"%(mainstring)

输入

0045662100456621004566210045662100456621

输出

琴弦长度:40

子字符串'00456621'在字符串'0045662100456621004566210045662100456621'中重复

输入

004608294930875576​​036866359447

输出

字符串长度:30

在字符串'004608294930875576​​576036866359447'中找不到重复的子字符串

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.