Mustererkennung innerhalb eines String-Objektes

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
uweddf
User
Beiträge: 12
Registriert: Freitag 30. August 2013, 10:28

Hallo,

ich habe ein String-Objekt.
In diesem String kommen nur die Zeichen '+' oder '-' vor, also niemals andere.
Das String-Objekt selber hat keine feste Länge.
Mein Ziel ist es, innerhalb des String-Objektes nach bestimmten Mustern zu suchen und diese dann zu zählen bzw. zu ersetzen.

Mir ist durchaus bewusst, dass count() in meinem Fall nicht zum gewünschten Ergebnis führen kann, da diese Funktion
Zeichenweise vorgeht und somit zum Beispiel die Zeichenkombination '+-+-+' nicht als zwei Treffer erkennt.
Erkannt werden : 1x '+-+' und '-+' bleibt dann zum weiterzählen übrig.
Sorry, auch wenn das, was ich als Ergebnis haben möchte, sehr einfach umsetzbar wäre, ist mir kein brauchbarer
Lösungsansatz hierzu eingefallen. Für ein wenig Hilfe wäre ich daher sehr dankbar.

Ich hätte da auch noch ein zweites Problem mit der Funktion replace(), welches ähnlich gelagert ist.
Sollte die Lösung von dem Problem count() nicht adaptierbar auf replace() sein, bitte ich auch hier um ein wenig Hilfe.

Vielen Dank.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# String = '++-+++-++++---++++-+++--+-+-+-++++++-+-+++'
# Muster = '+-+'
# Gewünschtes Ergebnis : '++-+++-++++---++++-+++--+-+-+-++++++-+-+++'
# ..........................|...|...........|......|.|.|......|.|...
# ..........................1...2...........3......4.5.6......7.8...

# Versuch mit count()
a = '++-+++-++++---++++-+++--+-+-+-++++++-+-+++'

e = a.count('+-+')  # Ergebnis : e = 6 und das ist leider != 8


# Versuch mit replace()
b = a.replace('+-+', 'x-x')

# Ergebnis : b = '+x-x+x-x+++---+++x-x++--x-x-x-x++++x-x-+++'
# gewollt  : b = '+x-x+x-x+++---+++x-x++--x-x-x-x++++x-x-x++'
# .......................................................|


BlackJack

@uweddf: Das zählen von überlappenden Treffern muss man selbst programmieren, aber das ist nicht weiter schwer:

Code: Alles auswählen

def count_overlapping(needle, haystack):
    result = 0
    index = -1
    while True:
        try:
            index = haystack.index(needle, index + 1)
            result += 1
        except ValueError:
            return result

Code: Alles auswählen

In [4]: count_overlapping('+-+', s)

Out[4]: 8
Das ersetzen ist ein wenig komplizierter. Aber auch machbar. Erster Schritt wäre aus der `count_overlapping()`-Funktion das finden der Indizes heraus zu ziehen würde ich sagen. Allerdings sind da auch Fragen offen denn das Beispiel reicht nicht wirklich als Spezifikation weil der Ersetzungsstring vom Muster her dem Suchstring entspricht. Darum macht es keinen Unterschied in welcher Reihenfolge man die Ersetzung vornimmt. Das muss ja aber nicht so sein.
uweddf
User
Beiträge: 12
Registriert: Freitag 30. August 2013, 10:28

@BlackJack: Vielen Dank für Deine schnelle Antwort.
Ich werde zuerst einmal die Funktion count_overlapping() versuchen zu verstehen und mit dem so hinzu gewonnen Wissen,
mein replace Problem versuchen zu lösen. Sollte dieses nicht funktionieren, werde ich mich noch einmal melden.

- Danke -
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Mit regulären Ausdrücken einfach zu lösen:

Code: Alles auswählen

def count_overlapping(pattern, string):
    return len(re.findall('(?=%s)'%re.escape(pattern), string)

def replace_overlapping(pattern, repl, string):
    return re.sub('([^x]{,%i})x'%len(pattern), lambda u:repl[-len(u.group(1)):], re.sub('(?<=%s)'%re.escape(pattern), 'x', x))
uweddf
User
Beiträge: 12
Registriert: Freitag 30. August 2013, 10:28

@Sirius3: Hallo Sirius3, vielen Dank für Deine fertige Lösung.

Ich hatte es bereits befürchtet, das mich dieses re Modul noch einmal quälen möchte.

Ich werde mich mit Deinem Lösungsvorschlag am Wochenende noch einmal auseinandersetzen um genau zu verstehen,
was die beiden Funktionen eigentlich wie tun.

Das einzig sinnvolle was ich bis jetzt mit dem re Modul zustande gebracht habe ist :
replace_pattern = re.compile('\t| |\n')

Selbst so triviale Ausdrücke wie: [a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*` lassen mich zur Zeit noch
leicht verzweifeln.

Vielen Dank,
für Deine beiden Lösungsvorschläge.
Antworten