匹配具有随机开头和/或结尾的字符串模式

时间:2020-08-07 17:36:06

标签: regex algorithm

假设我具有以下构造:

pattern = 'RepeatingMessage'
searchString = 'Aai23epjsditssageRepeatingMessageRepeatingMessageRepeatingMessageRepAsdjigrjiegj'

我如何制作剪切功能

'ssageRepeatingMessageRepeatingMessageRepeatingMessageRep'

可靠地使重复消息的开始和结束可以是随机的吗?

所以也可能是:

'sfdsfu338843ufsingMessageRepeatingMessageRepeatingMessafuaz8792afsmssage'

在您剪切的第二个字符串中

'ingMessageRepeatingMessageRepeatingMessa'

预先感谢

3 个答案:

答案 0 :(得分:1)

我以一个必须匹配的最小字符数为前提。

步骤1:构建状态机以计算匹配的字符数。此状态机将是循环的。构建此状态机时,应在数组中为每个节点建立索引。例如:

Node Nr:  0    1    2    3    4    5    6    7    8    ...
Node   :  R -> e -> p -> e -> a -> t -> i -> n -> g -> ...
Index:
'R' -> Node 0
'e' -> Node 1, 3, ...

然后您在两种状态之间切换:

  1. 不消耗:对于索引中的每个节点,输入当前字母并遍历,直到达到最小长度。如果达到最小长度,则进入消费状态,否则移至下一个字母。
  2. 消费:持续消费直到状态机爆发。转变为不消费状态。

经过测试的代码:


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RepeatingMatcher
{
    public static String match(String pattern, String input)
    {
        Map<Character, List<PatternNode>> index = PatternNode.buildPattern(pattern);
        
        StringBuilder filteredInput = new StringBuilder();
        
        for (int i = 0; i < input.length(); i++)
        {
            char c = input.charAt(i);
            List<PatternNode> idxl = index.get(c);
            if (idxl != null)
            {
                boolean looking = true;
                for (int j = 0; looking && j < idxl.size(); j ++)
                {
                    int matchCnt = idxl.get(j).consume(input, i, 0);
                    if (matchCnt >= pattern.length())
                    {
                        // - 1 because the for loop will increment it.
                        i += matchCnt - 1;
                        looking = false;
                    }
                }
                
                if (looking)
                {
                    filteredInput.append(c);
                }
            }
            else
            {
                filteredInput.append(c);
            }
        }
        
        return filteredInput.toString();
    }

    private static class PatternNode
    {
        private final char patternChar;
        private PatternNode next;

        PatternNode(char patternChar)
        {
            this.patternChar = patternChar;
        }

        int consume(String s, int idx, int cnt)
        {
            if (patternChar == s.charAt(idx))
            {
                cnt = cnt + 1;
                if (next != null)
                {
                    cnt = next.consume(s, idx + 1, cnt);
                }
            }

            return cnt;
        }

        static Map<Character, List<PatternNode>> buildPattern(String pattern)
        {
            Map<Character, List<PatternNode>> index = new HashMap<>();

            char c = pattern.charAt(0);
            PatternNode root = new PatternNode(c);
            List<PatternNode> idxl = index.getOrDefault(c, new ArrayList<>());
            index.put(c, idxl);
            idxl.add(root);
            PatternNode curr = root;
            for (int i = 1; i < pattern.length(); i++)
            {
                c = pattern.charAt(i);
                curr.next = new PatternNode(c);
                curr = curr.next;
                idxl = index.getOrDefault(c, new ArrayList<>());
                index.put(c, idxl);
                idxl.add(curr);
            }
            curr.next = root;

            return index;
        }
    }

}

答案 1 :(得分:1)

该问题包含正则表达式标记。根据您的用例,我不会完全建议这种方法,但无论如何我还是解决了。这是一个更简单,更易读的正则表达式,用于键“ word”:

((((w)?o)?r)?d)?(word)+(w(o(r(d)?)?)?)?

这是解决问题的完整正则表达式:

((((((((((((((((R)?e)?p)?e)?a)?t)?i)?n)?g)?M)?e)?s)?s)?a)?g)?e)?(RepeatingMessage)+(R(e(p(e(a(t(i(n(g(M(e(s(s(a(g(e)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?

答案 2 :(得分:0)

好的,谢谢您的答复。我无法获得适合我的Java代码,但我编写了一个似乎可以解决此问题的简单脚本。它从模式索引中向前和向后搜索,并检出:(powershell)

return 1