2016-11-02 5 views
1

Zunächst ist dies Hausaufgaben. (Ich konnte keinen Titel im Titel verwenden und nichts tauchte in der Tagliste unten für Hausaufgaben auf, also lass mich bitte wissen, ob ich etwas anderes in dieser Angelegenheit BEARBEITEN sollte).Python Regex passende Wörter mit sich wiederholenden Konsonanten

Also habe ich durch die Python-Dokumente gelesen und SO aufgefangen, mehrere Lösungen gefunden, die nahe an dem sind, was ich will, aber nicht genau.

Ich habe ein Wörterbuch, das ich in einen String lesen:

a 
aa 
aabbaa 
... 
z 

Wir auf diesen Daten verschiedene Regex prasselt üben. Das spezifische Problem hier ist, eine Liste der Wörter zurückzugeben, die dem Muster entsprechen, NICHT Tupel mit den Gruppen innerhalb jedes Matches.

Zum Beispiel:

eine Teilmenge dieses Wörterbuch Gegeben wie:

someword 
sommmmmeword 
someworddddd 
sooooomeword 

Ich möchte zurück:

['sommmmmword', 'someworddddd'] 

NICHT:

[('sommmmword', 'mmmmm', ...), ...] # or any other variant 

EDIT:

Meine Argumentation hinter dem obigen Beispiel ist, dass ich sehen möchte, wie ich vermeiden kann, einen zweiten Durchlauf über die Ergebnisse zu machen. Das heißt, anstatt zu sagen:

res = re.match(re.compile(r'pattern'), dictionary) 
return [r[0] for r in res] 

ich speziell einen Mechanismus will, wo ich gerade verwenden kann:

return re.match(re.compile(r'pattern'), dictionary) 

Ich weiß, dass dumm klingen, aber ich tue dies, um wirklich in regex zu graben. Ich erwähne das unten.

Dies ist, was ich versucht habe:

# learned about back refs 
r'\b([b-z&&[^eiou]])\1+\b' -> # nothing 

# back refs were weird, I want to match something N times 
r'\b[b-z&&[^eiou]]{2}\b' -> # nothing 

Irgendwo in Test ich ein Muster bemerkt Dinge wie '\nsomeword' zurück. Ich konnte nicht herausfinden, was es war, aber wenn ich das Muster wieder finde, werde ich es hier der Vollständigkeit halber hinzufügen.

# Maybe the \b word markers don't work how I think? 
r'.*[b-z&&[^eiou]]{2}' -> # still nothing 

# Okay lets just try to match something in between anything 
r'.*[b-z&&[^eiou]].*' -> # nope 

# Since its words, maybe I should be more explicit. 
r'[a-z]*[b-z&&[^eiou]][a-z]*' -> # still nope 

# Decided to go back to grouping. 
r'([b-z&&[^eiou]])(\1)' # I realize set difference may be the issue 

# I saw someone (on SO) use set difference claiming it works 
# but I gave up on it... 

# OKAY getting close 
r'(([b-df-hj-np-tv-xz])(\2))' -> [('ll', 'l', 'l'), ...] 

# Trying the the previous ones without set difference 
r'\b(.*(?:[b-df-hj-np-tv-xz]{3}).*)\b' -> # returned everything (all words) 

# Here I realize I need a non-greedy leading pattern (.* -> .*?) 
r'\b(.*?(?:[b-df-hj-np-tv-xz]{3}).*)\b' -> # still everything 

# Maybe I need the comma in {3,} to get anything 3 or more 
r'\b(.*?(?:[b-df-hj-np-tv-xz]{3,}).*)\b' -> # still everything 

# okay I'll try a 1 line test just in case 
r'\b(.*?([b-df-hj-np-tv-xz])(\2{3,}).*)\b' 
    # Using 'asdfdffff' -> [('asdfdffff', 'f', 'fff')] 
    # Using dictionary -> [] # WAIT WHAT?! 

Wie funktioniert das letzte? Vielleicht gibt es keine 3+ wiederholten konsonanten Wörter? Ich benutze /usr/share/dict/cracklib-small auf meinem Schulserver, der ungefähr 50.000 Wörter ist, denke ich.

Ich arbeite immer noch daran, aber jeder Rat wäre toll.

Eine Sache, die ich seltsam finde, ist, dass Sie nicht auf eine nicht einfangende Gruppe verweisen können. Wenn ich nur das vollständige Wort ausgeben möchte, verwende ich (?: ...), um eine Erfassung zu vermeiden, aber dann kann ich keine Referenz zurückgeben. Natürlich konnte ich die Captures verlassen, die Ergebnisse überfliegen und die zusätzlichen Sachen herausfiltern, aber ich möchte das unbedingt mit NUR Regex herausfinden!

Vielleicht gibt es eine Möglichkeit, das Nicht-Capture zu tun, aber immer noch zurück Referenz? Oder vielleicht gibt es einen ganz anderen Ausdruck, den ich noch nicht getestet habe.

+0

Hausaufgaben in Ordnung ist hier zu fragen, wenn Sie Anstrengungen wettgemacht haben :) Können Sie bitte die Logik hinter "['sommmmmmword', 'someworddddd']' und nicht '[('sommmmword', 'mmmmm', ...), ...] teilen 'Auf welcher Grundlage diese beiden unterschieden werden ? –

+0

Ah ja, tut mir leid, wenn das verwirrend schien. Ich habe einen Schnitt eingefügt. – spanishgum

+0

1) Verwende 're.findall', um alle Ergebnisse zu erhalten, nicht' re.match' (das sucht nur nach 1 Übereinstimmung und nur beim String-Start). 2) '[b-z && [^ eiou]]' ist ein Java/ICU-Regex, diese Syntax wird von Python 're' nicht unterstützt. 3) Um "Extra" -Werte in Tupeln mit 're.findall' zu vermeiden, * verwenden Sie keine einfangenden Gruppen. Wenn Sie Rückverweise benötigen, verwenden Sie 're.finditer' anstelle von' re.findall' und greifen Sie auf '.group()' jeder Übereinstimmung zu. –

Antwort

1

Hier sind einige Punkte zu beachten:

  1. Verwenden re.findall alle Ergebnisse zu erhalten, nicht re.match (das nur sucht nach 1 Ursache und nur an der String-Start).

  2. [b-z&&[^eiou]] ist ein Java/ICU Regex, diese Syntax wird von Python re nicht unterstützt. In Python können Sie die Bereiche entweder neu definieren, um die Vokale zu überspringen, oder (?![eiou])[b-z] verwenden.

  3. Um "extra" Werte in Tupeln mit re.findall zu vermeiden, nicht Verwendung einfangenden Gruppen tun. Wenn Sie Rückverweise benötigen, verwenden Sie re.finditer anstelle von re.findall und greifen Sie auf .group() jedes Treffers zu.

auf die Frage zurückzukommen, wie Sie eine Rückreferenzierung verwenden können und trotzdem das ganze Spiel bekommen, ist hier ein working demo:

import re 
s = """someword 
sommmmmeword 
someworddddd 
sooooomeword""" 
res =[x.group() for x in re.finditer(r"\w*([b-df-hj-np-tv-xz])\1\w*", s)] 
print(res) 
# => ['sommmmmeword', 'someworddddd'] 
+0

Ah, ich benutzte fiindall, ich habe das Beispiel einfach vertippt. Aber ich habe nicht versucht, Sichter! Ich dachte, es wäre nur ein Generator für alle. Ich werde das testen, sobald ich zu Hause bin! Vielen Dank. Als eine Nebenbemerkung, anstatt explizit '\ 1 \ 1 \ 1 \ 1 ...' zu sagen, um N Kopien der Übereinstimmung zu sammeln, könnte ich einfach \ 1 {N} ohne Gruppierung verwenden? – spanishgum

+0

Sie können einen Quantor mit einer Rückreferenz (= eine Rückreferenz quantifizieren) auf die gleiche Weise wie jedes Atom verwenden: '\ 1 {4}'. Siehe [diese Regex-Demo] (https://regex101.com/r/FU9R61/1). –

Verwandte Themen