Synonyme

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
new2python
User
Beiträge: 2
Registriert: Mittwoch 10. April 2019, 21:36

Hallo zusammen,

ich möchte folgendes tun:

in mehreren deutschen Text-Dateien möchte ich (mit Regular Expressions?) nach unterschiedlichen Schreibweisen für den gleichen Begriff suchen und wenn ich es finde, immer mit dem gleichen Begriff ersetzen. Zum Beispiel

"Str." oder "Strasse" oder "Straße" möchte ich immer als "Straße" erkennen und ersetzen

Das möchte ich mit 4 Begriffen tun und ich kenne für alle schon unterschiedliche Schreibweisen, die in den Dokumenten vorkommen und Synonyme.

Könnt ihr mir helfen? Ich bin ein absoluter Python-Einsteiger.

Danke!!!
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@new2python: In der Python-Dokumentation findest Du ein Tutorial für die Python-Grundlagen und ein Howto für reguläre Ausdrücke.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@new2python: Strings haben eine replace()-Methode. Damit kannst du Ersetzungen vornehmen. Ein erster Ansatz wäre also:

Code: Alles auswählen

text.replace('Str.', 'Straße').replace('Strasse', 'Straße')
Das ist allerdings nicht besonders effizient, wenn man es mit umfangreichen Texten und vielen zu tätigen Ersetzungen zu tun hat. Dann sollte man sich das re-Modul und hier inbesondere re.sub() anschauen, um reguläre Ausdrücke zum Finden und Ersetzen anzuwenden. Würde dann so aussehen:

Code: Alles auswählen

re.sub(r'Str\.|Strasse', 'Straße', text)
Etwas fortgeschrittener lässt sich dafür auch eine Funktion schreiben. Hier mal als lauffähiges Skript:

Code: Alles auswählen

import re

EXAMPLE = 'In der Str. ist eine Straße oder Strasse'

def replace(text, needles, replacement):
    pattern = '|'.join(map(re.escape, needles))
    return re.sub(pattern, replacement, text)

def main():
    replaced = replace(EXAMPLE, ['Str.', 'Strasse'], 'Straße')
    print(replaced)

if __name__ == '__main__':
    main()
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der Ansatz mit regulären Ausdrücken lässt sich übrigens weiter ausbauen, wenn man unterschiedliche Ersetzungen vornehmen möchte. Ich habe das hier mal als Klasse implementiert, wäre aber auch als Funktion mit entsprechendem Wörterbuch denkbar. Ich fand es mit der add_rule()-Methode jedoch anwenderfreundlicher.

Code: Alles auswählen

import re

EXAMPLE = """
Bernd Meier, Kurze Str. 42, Tel.: 12345
Lisa Müller, Lange Strasse 77, Tel.-Nr.: 67890
Hans Wurst, Hauptstraße 11, Telefon: 54745
"""

class Translator:
    def __init__(self):
        self.replacements = {}

    def add_rule(self, needles, replacement):
        for needle in needles:
            self.replacements[needle] = replacement

    def _replace(self, match):
        needle = match.group()
        return self.replacements[needle]

    def translate(self, text):
        # NOTE: "|" is always non-greedy!
        # -> take long needles first to avoid false positives
        size_sorted = sorted(self.replacements, key=len, reverse=True)
        pattern = '|'.join(map(re.escape, size_sorted))
        return re.sub(pattern, self._replace, text)

def main():
    trans = Translator()
    trans.add_rule(['Str.', 'Strasse'], 'Straße')
    trans.add_rule(['Tel.', 'Tel.-Nr.', 'Telefon'], 'Telefonnummer')
    print(trans.translate(EXAMPLE))

if __name__ == '__main__':
    main()
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei sorted() habe ich zu kompliziert gedacht. Es reicht, einfach rückwärts zu sortieren, ohne speziellem key. Im Hinblick darauf, dass die Regex-Engine als "dummer" endlicher Automat implementiert ist, dürfte das sogar etwas schneller laufen, da gleiche Wortanfänge unmittelbar aufeinander folgen (habe aber nicht nachgemessen).

Code: Alles auswählen

import re

EXAMPLE = """\
Bernd Meier, Kurze Str. 42, Tel.: 12345
Lisa Müller, Lange Strasse 77, Tel.-Nr.: 67890
Hans Wurst, Hauptstraße 11, Telefon: 54745"""

class Translator:
    def __init__(self):
        self.replacements = {}

    def add_rule(self, needles, replacement):
        for needle in needles:
            self.replacements[needle] = replacement

    def _replace(self, match):
        needle = match.group()
        return self.replacements[needle]

    def translate(self, text):
        replacements = sorted(self.replacements, reverse=True)
        pattern = '|'.join(map(re.escape, replacements))
        return re.sub(pattern, self._replace, text)

def main():
    trans = Translator()
    trans.add_rule(['Str.', 'Strasse'], 'Straße')
    trans.add_rule(['Tel.', 'Tel.-Nr.', 'Telefon'], 'Telefonnummer')
    print(trans.translate(EXAMPLE))

if __name__ == '__main__':
    main()
new2python
User
Beiträge: 2
Registriert: Mittwoch 10. April 2019, 21:36

Danke!!!!
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Fun Fact: Der simple Ansatz über die wiederholte Anwendung von text.replace() ist auch bei längeren Texten deutlich schneller als der Weg über die Regex-Engine. Folglich ist es in dieser Form flotter:

Code: Alles auswählen

EXAMPLE = """\
Bernd Meier, Kurze Str. 42, Tel.: 12345
Lisa Müller, Lange Strasse 77, Tel.-Nr.: 67890
Hans Wurst, Hauptstraße 11, Telefon: 54745"""

class Translator:
    def __init__(self):
        self.replacements = {}

    def add_rule(self, needles, replacement):
        for needle in needles:
            self.replacements[needle] = replacement

    def translate(self, text):
        for needle in sorted(self.replacements, reverse=True):
            text = text.replace(needle, self.replacements[needle])
        return text

def main():
    trans = Translator()
    trans.add_rule(['Str.', 'Strasse'], 'Straße')
    trans.add_rule(['Tel.', 'Tel.-Nr.', 'Telefon'], 'Telefonnummer')
    print(trans.translate(EXAMPLE))

if __name__ == '__main__':
    main()
Antworten