Zählen Sie die Buchstaben in einem Text in walisischer Sprache

78

Wie zähle ich die Buchstaben in Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch?

print(len('Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'))

Sagt 58

Wenn es so einfach wäre, würde ich dich nicht fragen, oder?!

Wikipedia sagt ( https://en.wikipedia.org/wiki/Llanfairpwllgwyngyll#Placename_and_toponymy )

Die lange Form des Namens ist mit 58 Zeichen der längste Ortsname im Vereinigten Königreich und einer der längsten der Welt (51 "Buchstaben", da "ch" und "ll" Digraphen sind und in der als einzelne Buchstaben behandelt werden Walisische Sprache).

Also möchte ich das zählen und die Antwort 51 erhalten.

Alles klar.

print(len(['Ll','a','n','f','a','i','r','p','w','ll','g','w','y','n','g','y','ll','g','o','g','e','r','y','ch','w','y','r','n','d','r','o','b','w','ll','ll','a','n','t','y','s','i','l','i','o','g','o','g','o','g','o','ch']))
51

Ja, aber das ist Betrug, natürlich möchte ich das Wort als Eingabe verwenden, nicht die Liste.

Wikipedia sagt auch, dass die Digraphen auf Walisisch ch, dd, ff, ng, ll, ph, rh, th sind

https://en.wikipedia.org/wiki/Welsh_orthography#Digraphs

Also los geht's. Addieren wir die Länge und nehmen dann die Doppelzählung ab.

word='Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'
count=len(word)
print('starting with count of',count)
for index in range(len(word)-1):
  substring=word[index]+word[index+1]
  if substring.lower() in ['ch','dd','ff','ng','ll','ph','rh','th']:
    print('taking off double counting of',substring)
    count=count-1
print(count)

Das bringt mich so weit

starting with count of 58
taking off double counting of Ll
taking off double counting of ll
taking off double counting of ng
taking off double counting of ll
taking off double counting of ch
taking off double counting of ll
taking off double counting of ll
taking off double counting of ll
taking off double counting of ch
49

Es scheint, dass ich damals zu viele abgezogen habe. Ich soll 51 bekommen. Jetzt ist ein Problem, dass mit dem lllles 3 lls gefunden und drei statt zwei abgenommen hat. Das muss also behoben werden. (Darf sich nicht überlappen.)

Und dann gibt es noch ein anderes Problem. Die ng. Wikipedia hat nichts darüber gesagt, dass der Name einen Buchstaben "ng" enthält, aber er ist als einer der Digraphen auf der Seite aufgeführt, die ich oben zitiert habe.

Wikipedia gibt uns etwas mehr Ahnung hier: „zusätzliche Informationen benötigt werden , um eine echte digraph aus einer Aneinanderreihung von Buchstaben zu unterscheiden“ . Und es gibt das Beispiel von " llongyfarch ", wo das ng nur ein "Nebeneinander von Buchstaben" ist, und " llong ", wo es ein Digraph ist.

Es scheint also, dass 'Llanfairpwllgwy ng yllgogerychwyrndrobwllllantysiliogogogoch' eines dieser Wörter ist, bei denen das -ng- nur ein "Nebeneinander von Buchstaben" ist.

Und offensichtlich kann der Computer das auf keinen Fall wissen. Also muss ich ihm die "zusätzlichen Informationen" geben, über die Wikipedia spricht.

Wie auch immer, ich habe mich entschlossen, in einem Online-Wörterbuch http://geiriadur.ac.uk/gpc/gpc.html nachzuschlagen, und Sie können das sehen, wenn Sie llongyfarch nachschlagen (das Beispiel aus Wikipedia, das das "Nebeneinander von Buchstaben" enthält). es zeigt es mit einer vertikalen Linie zwischen dem n und dem g an, aber wenn Sie "llong" nachschlagen, tut es dies nicht.

Screenshot aus dem Wörterbuch (llongyfarch)

Screenshot aus dem Wörterbuch (llong)

Also habe ich beschlossen, dass wir die zusätzlichen Informationen bereitstellen müssen, indem wir ein |wie in das Wörterbuch in die Eingabezeichenfolge einfügen, damit der Algorithmus weiß, dass das ngBit wirklich aus zwei Buchstaben besteht. Aber natürlich möchte ich nicht, dass das |selbst als Brief gezählt wird.

Jetzt habe ich folgende Eingaben:

word='llong'
ANSWER NEEDS TO BE 3 (ll o ng)

word='llon|gyfarch'
ANSWER NEEDS TO BE 9 (ll o n g y f a r ch)

word='Llanfairpwllgwyn|gyllgogerychwyrndrobwllllantysiliogogogoch'
ANSWER NEEDS TO BE 51 (Ll a n f a i r p w ll g w y n g y ll g o g e r y ch w y r n d r o b w ll ll a n t y s i l i o g o g o g o ch)

und immer noch diese Liste von Digraphen:

['ch','dd','ff','ng','ll','ph','rh','th']

und die Regeln werden sein:

  1. Fall ignorieren

  2. Wenn Sie einen Digraphen sehen, zählen Sie ihn als 1

  3. Arbeit von links nach rechts , so dass llllist ll+ llnicht l+ ll+l

  4. Wenn Sie sehen, dass Sie |es nicht zählen, aber Sie es nicht vollständig ignorieren können, ist es dazu ngda, kein Digraph mehr zu sein

und ich möchte, dass es als 51 zählt und es aus den richtigen Gründen tut, nicht nur als Zufall.

Jetzt bekomme ich 51, aber es macht es kaputt, weil es das |als einen Buchstaben zählt (1 zu hoch), und dann nimmt es einen zu viel mit dem llll(1 zu niedrig) ab - FEHLER ABBRECHEN

Es wird llongrichtig (3).

Es wird llon|gyfarchfalsch (10) - |wieder zählen

Wie kann ich es richtig beheben?

Madarch
quelle
Da es nur ein Wort ist, das Sie messen möchten, und Sie das Wort und seine Länge kennen, können Sie einfach eine konstante Zeichenfolge erstellen, die die Zeichenfolge enthält, und eine Konstante int, die die Länge der Zeichenfolge enthält, und damit fertig sein. Keine Notwendigkeit, dies im Code zu tun, oder?
Raddevus
Ich weiß nicht viel über Python. Könnten Sie nachher count=count-1hinzufügen index=index+1, um den nächsten Buchstaben zu überspringen?
Rhavelka
1
Ich weiß also nicht viel über Python, aber ich dachte, sie müssen ein Kulturkonzept für Streicher haben? In .NET würden Sie beispielsweise die Kultur Ihrer Anwendung festlegen und darauf basierend bestimmte Zeichen unterschiedlich behandeln. Wenn Sie hier nicht versuchen, dies von Grund auf selbst umzusetzen, ignorieren Sie diesen Kommentar.
Max Young
Wenn es C # wäre, könnte ich anbieten "ch dd ff ng ll ph rh th |".Split().ToList().ForEach(a => sb.Replace(a, a == "|" ? ".": "")); //sb is a stringbuilder- ersetzen Sie einfach jeden der Digraphen durch ein Zeichen, das nicht in der Zeichenfolge vorkommt, und ersetzen Sie das Zeichen schließlich durch |nichts. Die resultierende Länge ist Ihre Zeichenfolge. Kein Python-Entwickler, aber der gleiche Prozess sollte funktionieren, die Doppel durch ein Einzel zu ersetzen.
Caius Jard
2
"th" und "sh" sind Digraphen auf Englisch, aber ich bin noch nie auf jemanden gestoßen, der diese "einzelnen Buchstaben" im Glyphensinn betrachtet. Sie fragen nach dem Zählen von " Phonemen ", die notorisch unangenehm auf mit Alphabeten geschriebene Sprachen abgebildet werden. Der Silbenbruch, den Sie identifiziert haben, ist nur eine Mehrdeutigkeit.
Xophmeister

Antworten:

58

Wie viele Probleme mit Strings kann dies mit einem regulären Ausdruck auf einfache Weise geschehen.

>>> word = 'Llanfairpwllgwyn|gyllgogerychwyrndrobwllllantysiliogogogoch'
>>> import re
>>> pattern = re.compile(r'ch|dd|ff|ng|ll|ph|rh|th|[^\W\d_]', flags=re.IGNORECASE)
>>> len(pattern.findall(word))
51

Die Zeichenklasse [^\W\d_](von hier aus ) stimmt mit Wortzeichen überein, die keine Ziffern oder Unterstriche sind, dh Buchstaben, einschließlich solcher mit diakritischen Zeichen.

kaya3
quelle
Ist die Reihenfolge der Bedingungen dort wichtig? Wird ich Vorrang vor a bis z haben, da es zuerst erscheint? Genauer gesagt, ist das eine Regex-spezifische Sache oder wird jede Sprache ihre eigene Implementierung haben?
Max Young
Wenn Sie möchten, dass Regex die Ursprungseingabe verarbeitet:pattern = re.compile(r'ch|dd|ff|ll|ph|rh|th|[a-z]|(ng^yf)', flags=re.IGNORECASE)
benjessop
3
@MaxYoung Ja, die Reihenfolge der Teile ist der Grund, warum die Digraphen Vorrang vor einzelnen Buchstaben haben. Das gilt im Allgemeinen für jede Regex-Engine, die ich gesehen habe. In Python heißt es in den Dokumenten speziell : "Beim Scannen der Zielzeichenfolge werden REs durch '|' getrennt. werden von links nach rechts versucht " , so ist es das angegebene Verhalten und sicher zu verlassen.
kaya3
7
Dann gibt es das Problem, dass Walisisch mehrere Lehnwörter / -phrasen aus dem Englischen verwendet und deren Schreibweise nicht immer in walisische Schreibweise ändert, sodass Sie nicht unbedingt darauf zählen können, dass die Digraphen Digraphen sind ...: - | Ah, natürliche Sprachen machen so viel Spaß . :-)
TJ Crowder
2
@benjessop, worum geht es (ng^yf)? Kann es jemals mit etwas übereinstimmen, wenn ^dies den Beginn der Zeichenfolge bedeutet?
ilkkachu
19

Sie können die Länge ermitteln, indem Sie alle Doppelbuchstaben durch ein .(oder ein anderes Zeichen, ?das in Ordnung ist) ersetzen und die Länge der resultierenden Zeichenfolge messen (die Menge von subtrahieren |):

def get_length(name):
    name = name.lower()
    doubles = ['ch', 'dd', 'ff', 'ng', 'll', 'ph', 'rh', 'th']
    for double in doubles:
        name = name.replace(double, '.')
    return len(name) - name.count('|')

name = 'Llanfairpwllgwyn|gyllgogerychwyrndrobwllllantysiliogogogoch'
print(get_length(name))
>>> 51
Nathan
quelle
+1 weil es extrem einfach ist, hätte ich nie gedacht, nur die Zeichen, die konjugiert sind, zu kennzeichnen, da es an besseren Begriffen mangelt. Ich habe das Gefühl, dass ich dies auf einen Algorithmus anwenden muss, an dem ich gearbeitet habe, um doppelte Zeichen in japanischem Text zu erkennen, aber wo die Duplizierung korrekt ist. Das Problem, auf das ich auf Japanisch stoße, ist, dass zum Beispiel hahaha drei gleiche Zeichen hintereinander sind, aber das könnten theoretisch die ersten beiden Zeichen sein, die ich ausspreche, und das letzte Zeichen ist ein Partikel.
Max Young
In diesem Fall funktioniert es gut. Wenn Sie diese Methode auf andere Zeichenfolgen anwenden, müssen Sie sicherstellen, dass die Zwischenvariable keine Digraphen enthält, die in der ursprünglichen Zeichenfolge nicht vorhanden sind.
Eric Duminil
9
  1. Schritt für Buchstabe durch die Zeichenfolge gehen
  2. Wenn Sie sich am Index n befinden und und s [n: n + 2] ein Digraph ist, fügen Sie ein Wörterbuch mit dem Digraphen als Schlüssel hinzu oder erhöhen Sie es, und erhöhen Sie den Index ebenfalls um 1, damit Sie nicht mit dem zweiten Digraphen beginnen Charakter. Wenn es sich nicht um einen Digraphen handelt, fügen Sie einfach den Buchstaben zum Diktat hinzu oder erhöhen Sie ihn und fahren Sie mit dem nächsten Buchstaben fort.
  3. Wenn Sie die | sehen Charakter, zähle es nicht, überspringe einfach.
  4. Und vergessen Sie nicht, Kleinbuchstaben zu schreiben.

Wenn Sie alle Buchstaben gesehen haben, endet die Schleife und Sie fügen alle Zählungen im Diktat hinzu.

Hier ist mein Code, er funktioniert anhand Ihrer drei Beispiele:

from collections import defaultdict

digraphs=['ch','dd','ff','ng','ll','ph','rh','th']
breakchars=['|']


def welshcount(word):
    word = word.lower()
    index = 0
    counts = defaultdict(int)  # keys start at 0 if not already present
    while index < len(word):
        if word[index:index+2] in digraphs:
            counts[word[index:index+2]] += 1
            index += 1
        elif word[index] in breakchars:
            pass  # in case you want to do something here later
        else:  # plain old letter
            counts[word[index]] += 1

        index += 1

    return sum(counts.values())

word1='llong'
#ANSWER NEEDS TO BE 3 (ll o ng)

word2='llon|gyfarch'
#ANSWER NEEDS TO BE 9 (ll o n g y f a r ch)

word3='Llanfairpwllgwyn|gyllgogerychwyrndrobwllllantysiliogogogoch'
#ANSWER NEEDS TO BE 51 (Ll a n f a i r p w ll g w y n g y ll g o g e r y ch w y r n d r o b w ll ll a n t y s i l i o g o g o g o ch)

print(welshcount(word1))
print(welshcount(word2))
print(welshcount(word3))
Carlos
quelle
1

Sie können ein kombinierendes Grapheme Joiner-Zeichen (+ u034F) verwenden, um die Buchstaben zu verbinden. Nehmen Sie dann die Anzahl Ihrer Zeichen und entfernen Sie die Anzahl dieser Joiner * 2.

http://www.comisiynyddygymraeg.cymru/English/Part%203/10%20Locales%20alphabets%20and%20character%20sets/10.2%20Alphabets/Pages/10-2-4-Combining-Grapheme-Joiner.aspx

Der walisische Sprachkommissar spricht das Problem auch hier an: http://www.comisiynyddygymraeg.cymru/English/Part%203/10%20Locales%20alphabets%20and%20character%20sets/10.2%20Alphabets/Pages/10-2-1- Character-vs - letter-count.aspx

James Rushford
quelle