在字符串中查找最短的重复模式

时间:2015-03-10 12:11:12

标签: regex matlab pattern-matching octave maple

我想知道是否有办法在Octave / matlab中进行模式匹配?我知道Maple 10有命令这样做但不确定我需要在Octave / Matlab中做什么。因此,如果数字为12341234123412341234,则模式匹配为1234。我试图找到重复生成整个字符串的最短模式

请注意:数字(仅使用数字)不会这么简单。另外,我不会提前知道模式(那是我想要找到的)。请参阅下面的Maple 10 example,其中显示该模式未提前知道,但命令会找到模式。

Maple 10模式匹配的示例:

ns:=convert(12341234123412341234,string);

             ns := "12341234123412341234"

StringTools:-PrimitiveRoot(ns);

             "1234"

如何在Octave / Matlab中执行此操作? Ps:我使用Octave 3.8.1

4 个答案:

答案 0 :(得分:10)

要找到重复生成整个字符串的最短模式,可以按如下方式使用正则表达式:

result = regexp(str, '^(.+?)(?=\1*$)', 'match');

一些例子:

>> str = '12341234123412341234';
>> result = regexp(str, '^(.+?)(?=\1*$)', 'match')
result = 
    '1234'

>> str = '1234123412341234123';
>> result = regexp(str, '^(.+?)(?=\1*$)', 'match')
result = 
    '1234123412341234123'

>> str = 'lullabylullaby';
>> result = regexp(str, '^(.+?)(?=\1*$)', 'match')
result = 
    'lullaby'

>> str = 'lullaby1lullaby2lullaby1lullaby2';
>> result = regexp(str, '^(.+?)(?=\1*$)', 'match')
result = 
    'lullaby1lullaby2'

答案 1 :(得分:3)

我不确定这是否可以用正则表达式完成。这是一个脚本,可以在一个名为pattern的重复单词的情况下执行所需的操作。

它循环遍历名为str的字符串的字符,尝试匹配另一个名为pattern的字符串。如果匹配失败,则会根据需要扩展pattern字符串。

编辑:我让代码更紧凑。

str = 'lullabylullabylullaby';

pattern = str(1);
matchingState = false;
sPtr = 1;
pPtr = 1;

while sPtr <= length(str)
     if str(sPtr) == pattern(pPtr) %// if match succeeds, keep looping through pattern string
            matchingState = true;
            pPtr = pPtr + 1;
            pPtr = mod(pPtr-1,length(pattern)) + 1;
     else                          %// if match fails, extend pattern string and start again
            if matchingState
                sPtr = sPtr - 1;   %// don't change str index when transitioning out of matching state
            end  
            matchingState = false;
            pattern = str(1:sPtr);
            pPtr = 1;
     end

     sPtr = sPtr + 1;

end

display(pattern);

输出结果为:

pattern =

lullaby

注意:

这不允许pattern字符串出现之间的任意分隔符。例如,如果str = 'lullaby1lullaby2lullaby1lullaby2';,那么

pattern =

lullaby1lullaby2

这也允许pattern在不改变结果的情况下在一个循环中途结束。例如,str = 'lullaby1lullaby2lullaby1';仍将导致

pattern =

lullaby1lullaby2

要解决此问题,您可以添加行

if pPtr ~= length(pattern)
    pattern = str;
end

答案 2 :(得分:2)

另一种方法如下:

  1. 确定字符串的长度,并找到字符串长度值的所有可能因素
  2. 对于每个可能的因子长度,重塑字符串并检查 对于重复的子串
  3. 要查找所有可能的因素,请参阅SO上的this解决方案。下一步可以通过多种方式执行,但我在一个简单的循环中实现它,从最小的因子长度开始。

    function repeat = repeats_in_string(str);
    ns = numel(str);
    nf = find(rem(ns, 1:ns) == 0);
    for ii=1:numel(nf)
        repeat = str(1:nf(ii));
        if all(ismember(reshape(str,nf(ii),[])',repeat)); 
            break;
        end
    end 
    

答案 3 :(得分:0)

对于您解决问题的方法,此问题是Rorschach的一项很好的测试。我将添加一个信号工程解决方案,该解决方案应该很简单,因为在这种情况下,预计该信号将具有完美的重复性:找到重复时生成整个字符串的最短模式。

在以下传递给函数的str中,实际上是浮点数的列向量,而不是字符串,原始字符串已用str2num(str2mat(str)')进行了转换:

function res=findshortestrepel(str);
[~,ii] = max(fft(str-mean(str)));
res = str(1:round(numel(str)/(ii-1)));

我进行了一次小型测试,将其与regexp解决方案进行比较,发现它总体上更快(蓝色方块),尽管有些不一致,并且仅当您不考虑转换字符串所需的时间时变成浮点向量(绿色方块)。但是,我没有进一步追求这一点(没有打破记录):

enter image description here

以秒为单位的时间。