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 Réponses :
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:
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, ...
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.
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
'@
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)?)?)?)?
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.
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