Contare le lettere in un testo in lingua gallese
Come si contano le lettere in Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch?
print(len('Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'))
Dice 58
Beh, se fosse così facile non te lo chiederei, adesso lo farei ?!
Wikipedia dice (https://en.wikipedia.org/wiki/Llanfairpwllgwyngyll#Placename_and_toponymy)
La forma lunga del nome è il nome di luogo più lungo nel Regno Unito e uno dei più lunghi al mondo con 58 caratteri (51 "lettere" poiché "ch" e "ll" sono digrafi e sono trattati come singole lettere nel Lingua Gallese).
Quindi voglio contarlo e ottenere la risposta 51.
Okey dokey.
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
Sì, ma questo è un inganno, ovviamente voglio usare la parola come input, non l'elenco.
Wikipedia dice anche che i digrafi in gallese sono ch, dd, ff, ng, ll, ph, rh, th
https://en.wikipedia.org/wiki/Welsh_orthography#Digraphs
Quindi via. Sommiamo la lunghezza e poi togliamo il doppio conteggio.
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)
Questo mi porta fin qui
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
Sembra che allora ne abbia sottratti troppi. Dovrei ottenere 51. Ora un problema è che con llll
ha trovato 3 se ne ha ll
tolti tre invece di due. Quindi sarà necessario risolverlo. (Non deve sovrapporsi.)
E poi c'è un altro problema. Il ng
. Wikipedia non ha detto nulla sulla presenza di una lettera "ng" nel nome, ma è elencato come uno dei digrafi nella pagina che ho citato sopra.
Wikipedia ci fornisce qualche indizio in più qui: "potrebbero essere necessarie ulteriori informazioni per distinguere un vero digrafo da una giustapposizione di lettere" . E fornisce l'esempio di " llongyfarch " dove ng è solo una "giustapposizione di lettere" e " llong " dove è un digrafo.
Quindi sembra che 'Llanfairpwllgwy ng yllgogerychwyrndrobwllllantysiliogogogoch' sia una di quelle parole in cui -ng- è un po 'solo una "giustapposizione di lettere".
E ovviamente non c'è modo che il computer possa saperlo. Quindi dovrò fornire quelle "informazioni aggiuntive" di cui parla Wikipedia.
Comunque, ho deciso di cercare in un dizionario online http://geiriadur.ac.uk/gpc/gpc.htmle puoi vedere che se cerchi llongyfarch (l'esempio di Wikipedia che ha la "giustapposizione di lettere") lo visualizza con una linea verticale tra la ne la g ma se cerchi "llong" allora non Fai questo.


Quindi ho deciso che quello che dobbiamo fare è fornire le informazioni aggiuntive inserendo una |
nella stringa di input come fa nel dizionario, solo in modo che l'algoritmo sappia che il ng
bit è in realtà due lettere. Ma ovviamente non voglio che lo |
stesso sia considerato una lettera.
Quindi ora ho questi input:
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)
e ancora questo elenco di digrafi:
['ch','dd','ff','ng','ll','ph','rh','th']
e le regole saranno:
ignora maiuscole e minuscole
se vedi un digrafo, conta come 1
lavorare da sinistra a destra in modo che
llll
siall
+ll
, nonl
+ll
+l
se vedi un
|
non contarlo, ma non puoi ignorarlo completamente, è lì per smettere ding
essere un digrafo
e voglio che lo conti come 51 e che lo faccia per le giuste ragioni, non solo per caso.
Ora ottengo 51 ma è fluente perché conta il |
come una lettera (1 troppo alto), e quindi ne toglie uno di troppo con llll
(1 troppo basso) - ERRORI ANNULLATI
Sta andando llong
bene (3).
Sta llon|gyfarch
sbagliando (10) - contando di |
nuovo
Come posso risolverlo nel modo giusto?
Risposte
Come molti problemi che hanno a che fare con le stringhe, questo può essere fatto in modo semplice con una regex.
>>> 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
La classe di caratteri [^\W\d_]
(da qui ) corrisponde a caratteri parola che non sono cifre o trattini bassi, cioè lettere, comprese quelle con segni diacritici.
Puoi ottenere la lunghezza sostituendo tutte le doppie lettere con un .
(o qualsiasi altro carattere, ?
andrebbe benissimo) e misurando la lunghezza della stringa risultante (sottraendo la quantità di |
):
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
- Scorri la stringa lettera per lettera
- Se sei all'indice ne e s [n: n + 2] è un digrafo, aggiungi o incrementa un dizionario con il digrafo come chiave e incrementa anche l'indice di 1 in modo da non iniziare con il secondo digrafo personaggio. Se non è un digrafo, aggiungi o incrementa la lettera al dict e vai alla lettera successiva.
- Se vedi il | carattere, non contarlo, salta e basta.
- E non dimenticare di scrivere in minuscolo.
Quando hai visto tutte le lettere, il ciclo termina e aggiungi tutti i conteggi nel dict.
Ecco il mio codice, funziona sui tuoi tre esempi:
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))
Potresti usare un personaggio Combining Grapheme Joiner (+ u034F) per unire le lettere e poi prendere il conteggio dei tuoi caratteri e togliere il numero di questi joiners * 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
Anche il Welsh Language Commissioner affronta la questione qui: http://www.comisiynyddygymraeg.cymru/English/Part%203/10%20Locales%20alphabets%20and%20character%20sets/10.2%20Alphabets/Pages/10-2-1-Character-vs--letter-counts.aspx