1
votes

Faire correspondre le modèle de chaîne avec un début et / ou une fin aléatoires

Supposons que j'ai la construction suivante:

'ingMessageRepeatingMessageRepeatingMessa'

Comment puis-je créer une fonction qui coupe

'sfdsfu338843ufsingMessageRepeatingMessageRepeatingMessafuaz8792afsmssage'

de manière fiable, de sorte que démarrer et la fin du message répété pourrait être aléatoire?

donc cela pourrait aussi être:

'ssageRepeatingMessageRepeatingMessageRepeatingMessageRep'

dans la deuxième chaîne que vous avez coupée

pattern = 'RepeatingMessage'
searchString = 'Aai23epjsditssageRepeatingMessageRepeatingMessageRepeatingMessageRepAsdjigrjiegj'

Merci d'avance


3 commentaires

Le modèle est-il continuellement une seule fois dans la chaîne ou pourriez-vous avoir quelque chose comme «messageRepeatingMessageRepooooooageRepeatingMessageRe»?


Y a-t-il une longueur minimale qui doit correspondre? Par exemple, RepeatingMessage contient «a» et votre chaîne d'origine «Aai23epjsditssageRepeatingMessageRepeatingMessageRepeatingM‌ essageRepAsdjigrjieg‌ j» contient «a» en 2ème position. Pourquoi cela ne correspondait-il pas?


oui disons que le minimum de caractères est le motif entier au moins une fois


3 Réponses :


1
votes

Je base cette réponse sur l'hypothèse qu'il y a un nombre minimum de caractères qui DOIVENT être mis en correspondance.

Étape 1: construisez une machine à états pour compter le nombre de caractères correspondants. Cette machine à états sera circulaire. Lors de la construction de cette machine à états, chaque nœud doit être indexé dans un tableau. Par exemple:

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;
        }
    }

}

Ensuite, vous passez entre 2 états:

  1. Ne consomme pas: pour chaque nœud de l'index, alimentez la lettre actuelle et parcourez jusqu'à ce que la longueur minimale soit atteinte. Si la durée minimale est atteinte, entrez l'état de consommation, sinon passez à la lettre suivante.
  2. Consommation: continuez à consommer jusqu'à ce que la machine d'état éclate. Passer à l'état de non-consommation.

Code testé:

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, ...


3 commentaires

oui, disons que les caractères minimum sont le motif entier. pouvez-vous donner un code qui ressemblerait à ceci dans n'importe quelle langue que vous aimez? Je comprends le concept mais j'ai probablement du mal à le mettre en œuvre


hé, j'ai essayé votre code mais je n'ai pas pu le faire fonctionner. J'ai fait un script qui le fait pour moi maintenant. je le poste dans une réponse


Je l'ai testé et corrigé quelques fautes de frappe (entrée et motif échangés à 2 ou 3 endroits) et une erreur off-by-1. Cela fonctionne bien maintenant, même si je m'attendais à ce que vous déboguiez autant.



0
votes

Très bien, merci pour toutes les réponses. Je n'ai pas pu faire fonctionner le code java pour moi, mais j'ai créé un script simple qui semble fonctionner pour cela. Il recherche en avant et en arrière à partir des index de modèle, vérifiez-le: (powershell)

function Match-Pattern {
    [CmdletBinding()]
    param (
        [string]
        $Pattern,
        [string]
        $SearchString
    )
    
    begin {
        $patternRev = ([regex]::Matches($pattern, '.', 'RightToLeft') | 
            ForEach-Object { $_.value }) -join ''

        "Searching for all pattern occurances (with varying starts/ends):"
        "$Pattern`n"
        "in search string:"
        "$SearchString`n"

        $workingString = $SearchString
        while ($workingString.Contains($pattern)) {
            # get first starting point of repeat (min length is pattern length)
            $startIndexPattern = $workingString.IndexOf($pattern)
            # search behind for starting index
            $i = 1
            while ($workingString[$startIndexPattern - $i] -eq $patternRev[$i - 1]) {
                $startIndex = $startIndexPattern - $i
                $i++
            }
            # find last index of first pattern repetition
            $i = 1
            $multiplier = 0
            while ($workingString[$startIndexPattern + $pattern.Length * $multiplier - 1 + $i] -eq $pattern[$i - 1]) {
                $lastPatternStartIndex = $startIndexPattern + $pattern.Length * $multiplier - 1 + $i
                if ($i -eq $pattern.Length) {
                    $multiplier++
                    $i = 1
                } else {
                    $i++
                }
            }
            # $lastPatternStartIndex = $workingString.LastIndexOf($pattern)
            $lastPatternStartIndex++
            # cut string with indexes we found
            $substringLength = $lastPatternStartIndex - $startIndex
            $substring = $workingString.Substring($startIndex, $substringLength)

            "Found:"
            "$substring`n"

            "Cutting from workingString..:"
            $workingString = $workingString.Remove($workingString.IndexOf($substring),$substring.Length)
            "$workingString`n"
        }
    }
}

Match-Pattern -Pattern 'RepeatingMessage' `
    -SearchString @'
Aai23epjsditssageRepeatingMessageRepeatingMessageRepeatingMessageRepAsdjigrjiegj
Aai23epjsditssapeatingMessageRepeatingMessageRepeatingMessagcAsdjigrjiegj
Aai23epjsgeRepeatingMessageRepeatingMessageRepeatingMessageRepeaAsdjigrjiegj
'@


0 commentaires

1
votes

La question contient la balise regex. Je ne suggérerais pas entièrement cette méthode en fonction de votre cas d'utilisation, mais je l'ai quand même résolue. Le voici dans une regex plus simple et plus lisible pour le mot clé:

((((((((((((((((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)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?

Voici la regex complète pour résoudre le problème dans la question:

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


1 commentaires

C'est bien, cela peut bien fonctionner en créant une fonction qui génère l'expression régulière pour une chaîne particulière. Bien qu'il échoue pour des cas comme "epeatingMessa" lorsque la chaîne complète n'apparaît pas.