Seite 1 von 1

Regular Expressions definierte Stelle (eine von3) ersetzen

Verfasst: Montag 10. September 2012, 17:27
von flummi
Folgendes Problem:

ich hab einen String wie z.b. "du, bist du bist du bist du"

ich möchte aus "du" -> "ich" machen aber nur das zweite du! am besten unter angabe des index wo "du" anfängt. in diesem fall sprich String[9]

ps: re.sub("du","ich",string, count=X) funktioniert nicht, da es nur von links nach rechts zählt und man nicht auswählen kann!

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Montag 10. September 2012, 18:02
von flummi
Alternative:

String "du, bist du bist du bist du"

wenn ich weiß wo das 2te du anfängt, wie kann ich das 2te du RAUSSCHNEIDEN (ähnlich wie split) und den Rest als Liste mit 2 attributen zurückgeben?

dann könnte ich nachher einen neuen string erstellen indem ich die liste anzapfe und den gewünschten String in der mitte einführe.

Bin auch offen für jede andere lösung ,)

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Montag 10. September 2012, 18:55
von sparrow
Du kannst einen String durch das Suchwort splitten und die Teile anschließend wieder zusammenfügen, außer an der Stelle wo die Ersetzung vorgenommen werden soll.
Das geht bestimmt auch mit Regular Expressions, aber ich mag die nicht besonders.

Code: Alles auswählen

def mreplace(string, old, new, occurance):
    splits = string.split(old)
    if len(splits) < occurance:
        raise ValueError("'%s' does not occures %i times in '%s'" 
                          % (old, occurance, string))
    return new.join((old.join(splits[0:occurance]), 
                     old.join(splits[occurance:])))
    

a = "du, bist du bist du bist du"

print mreplace(a, "du", "ich", 2)

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Montag 10. September 2012, 18:56
von Hyperion
Wie wäre es damit:

Code: Alles auswählen

def replace(s, word, repl):
    pos = s.index(word, 1)
    return "{}{}{}".format(s[:pos], repl, s[pos+len(word):])

replace(s, "du", "ich")
>>> 'du, bist ich bist du bist du'

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Montag 10. September 2012, 19:24
von sparrow
Holla die Waldfee. Eigentlich hätte ich gedacht, dass Hyperions Lösung deutlich schneller ist, da ich ja erst den ganzen String splitte und ihn hinterher wieder zusammensetze. Aber

Code: Alles auswählen

import time

def mreplace(string, old, new, occurance):
    splits = string.split(old)
    if len(splits) < occurance:
        raise ValueError("'%s' does not occures %i times in '%s'" 
                          % (old, occurance, string))
    return new.join((old.join(splits[0:occurance]), 
                     old.join(splits[occurance:])))
    

def replace(s, word, repl):
    pos = s.index(word, 1)
    return "{}{}{}".format(s[:pos], repl, s[pos+len(word):])


a = "du, bist du bist du bist du"

start1 = time.time()
print mreplace(a, "du", "ich", 2)
stop1 = time.time()

start2 = time.time()
print replace(a, "du", "ich")
stop2 = time.time()

print stop1 - start1
print stop2 - start2
Bringt:

Code: Alles auswählen

du, bist ich bist du bist du
du, bist ich bist du bist du
0.000127077102661
5.41210174561e-05
CPython 2.7.3

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Montag 10. September 2012, 19:46
von Hyperion
Also zunächst einmal misst man solche Sachen mit dem `timeit`-Modul:

Code: Alles auswählen

#!/usr/bin/env python

import time

def replace_sparrow(string, old, new, occurance=2):
    splits = string.split(old)
    if len(splits) < occurance:
        raise ValueError("'%s' does not occure %i times in '%s'"
                          % (old, occurance, string))
    return new.join((old.join(splits[0:occurance]),
                     old.join(splits[occurance:])))
   

def replace_hyperion(s, word, repl):
    pos = s.index(word, 1)
    return "{}{}{}".format(s[:pos], repl, s[pos+len(word):])



def main():
    import timeit

    a = "du, bist du bist du bist du"


    for func in [replace_sparrow, replace_hyperion]:
        t = timeit.Timer("{0}('{1}', '{2}', '{3}')".format(func.__name__, a, 
                                                           "du", "ich"),
                         "from __main__ import {0}".format(func.__name__))
        count = 10000000
        print(func.__name__, (t.timeit(count) / count))


if __name__ == "__main__":
    main()
Das ergibt auf meinem alten System:

Code: Alles auswählen

replace_sparrow 3.6277180910110475e-06
replace_hyperion 3.4617495059967042e-06
./replace.py  69,86s user 0,01s system 98% cpu 1:11,01 total
Also liege ich da knapp vor Dir. Ich benutze aber auch Python 3.2.

Ich weiß ja nicht, was Du aus Deinem Ergebnis heraus gelesen hast, aber 5.4 * 10 ^ -5 ist imho deutlich kleiner als 1.2 * 10 ^ -4 ;-) Insofern wundert mich das "aber" bei Dir...

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Montag 10. September 2012, 19:48
von sparrow
Hyperion hat geschrieben:Ich weiß ja nicht, was Du aus Deinem Ergebnis heraus gelesen hast, aber 5.4 * 10 ^ -5 ist imho deutlich kleiner als 1.2 * 10 ^ -4 ;-) Insofern wundert mich das "aber" bei Dir...
Ah shit, die Zahl vor dem Komma hat mich so verwirrt, dass ich das Ende gar nicht mehr angeschaut habe. ;)

Gut, dann ist mein Weltbild jetzt ja wieder gerade :)

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 12:33
von flummi

Code: Alles auswählen

import re

def replace(string, word, repl, place):
    posl=[]
    for match in re.finditer(word, string):
          posl.append(match.start())
    pos=posl[place-1]
    return "{}{}{}".format(string[:pos], repl, string[pos+len(word):])
hab deine variante etwas umgeformt hyperion, damits allgemeingültiger ist.

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 12:54
von EyDu
Nun wird es aber echt Zeit für eine List Comprehension:

Code: Alles auswählen

pos1 = [match.start() for match in re.finditer(word, string)]
oder mittels map:

Code: Alles auswählen

pos1 = map(operator.methodcaller("start"), re.finditer(word, string))
Auch solltest du mal richtige Namen in betracht ziehen. "string" (was auch noch einen eingebauten Typen verdeckt) "repl", "place" und "pos1" sind alle sehr nichtssagend.

Die start-Methode würde ich auch nicht auf jedem item aufrufen, dass reicht ja im prinzip bei ``pos1[place-1].start()``.

Und das Erstellen der Liste kann man eigentlich auch sparen:

Code: Alles auswählen

pos = next(itertools.islice(re.finditer(word, string), place-1, place)).start()

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 13:21
von flummi
Vielen Dank, werde drüber nachdenken.

Nehmen wir an ich habe folgenden String

'[H]C(=O)CCC1=C(CC)C=C(CCCC)C(CC(=O)OC)=C1C'

es handelt sich um ein molekül im .smiles format.

Ich muss wissen wie weit die carbonylgruppen voneinander entfernt sind: C(=O)

Das Problem ist immer wenn klammern kommen wie zb, C1=C(CC)C hier, dann darf (CC) nicht mitgezählt werden, da es sich um eine verzweigung handelt und nicht zum direkten weg der carbonylgruppen beiträgt.

Allerdings taucht die zweite carbonylgruppe (eher carboxy, aber das sei jetzt mal egal) innerhalb von klammern auf, das macht aber nichts, da der weg ja trotzdem vorhanden ist. Im grunde lässt sich die smiles zeile in folgendes umschreiben:
'[H]C(=O)CCC1=C(CC)C=C(CCCC)C(=C1C)CC(=O)OC'

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 13:29
von EyDu
Und das ist der Grund, warum man in seine Problembeschreibung immer das "große Problem" hineinschreibt. Da beliebig tiefe Verschachtelungen möglich sind, kannst du das nicht mehr mit regulären Ausdrücken lösen, dafür brauchst du einen, wenn auch sehr trivialen, Parser. Noch einfacher ist das Problem aber, wenn du einfach mal nach "python smiles" suchst, es existieren dazu nämlich schon fertige Bibliotheken.

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 13:31
von flummi
cool danke, so kann man zeit sparen ;P
dafür hab ich etwas gelernt^^

schreibt man parser nicht mit regulären ausdrücken?

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 13:38
von EyDu
flummi hat geschrieben:schreibt man parser nicht mit regulären ausdrücken?
Nur um die Tokens zu extrahieren. Nur mit regulären Ausdrücken sind beliebige Verschachtelungstiefen mathematisch nicht möglich.

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 14:08
von flummi

Code: Alles auswählen

sekura@sekura-GA-MA770-UD3:~/frowns$ python setup.py build
running build
running build_py
running build
running build_ext
my_init_posix: changing gcc to g++
building '_pysssr' extension
g++ -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c pysssr.cxx -o build/temp.linux-i686-2.7/pysssr.o
cc1plus: Warnung: Kommandozeilenoption »-Wstrict-prototypes« ist gültig für Ada/C/ObjC, aber nicht für C++ [standardmäßig aktiviert]
pysssr.cxx:5:20: schwerwiegender Fehler: Python.h: Datei oder Verzeichnis nicht gefunden
Kompilierung beendet.
error: command 'g++' failed with exit status 1
Readme: pysssr requires a C++ compiler and is known to compile and work
under windows and linux/macosx using gcc 3.0 or higher.

sudo apt-get install gcc -->> gcc ist schon die aktuellste version

was muss ich machen? bzw. was funktioniert hier nicht?

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 14:15
von EyDu
Warum schaust du in die Readme, wenn die Fehlermeldung dort ganz eindeutig steht?
pysssr.cxx:5:20: schwerwiegender Fehler: Python.h: Datei oder Verzeichnis nicht gefunden
Wahrscheinlich fehlt bei dir einfach nur das python-dev Paket oder der dazugehörige Include-Pfad. Hast du mal geschaut, ob du das Projekt (welches auch immer) wirklich selber kompilieren musst und ob es nicht vielleicht schon im Paketmanager steckt?

Re: Regular Expressions definierte Stelle (eine von3) ersetz

Verfasst: Dienstag 11. September 2012, 14:29
von flummi
Also in der readme stand ich soll das so eingeben ;P

wie schau ich denn nach "ob es schon im packetmanager steckt". ja das ist bestimmt ne doofe frage aber ich hab linux seit 2 wochen drauf, und hab einiges aufzuholen ...
was passiert denn genau beim compilen?
da wird aus textdateien eine binary geschrieben oder nicht? Unter windows dann text -> .exe.

unter linux wird aus textdatei eine shell geschrieben die auch eine textdatei ist?!

also falls du sowas wie das ubuntu software center meinst, da liefert "frowns" keinen treffer.