Contare le lettere in un testo in lingua gallese

Aug 21 2020

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 llllha trovato 3 se ne ha lltolti 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 ngbit è 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:

  1. ignora maiuscole e minuscole

  2. se vedi un digrafo, conta come 1

  3. lavorare da sinistra a destra in modo che llllsia ll+ ll, non l+ ll+l

  4. se vedi un |non contarlo, ma non puoi ignorarlo completamente, è lì per smettere di ngessere 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 llongbene (3).

Sta llon|gyfarchsbagliando (10) - contando di |nuovo

Come posso risolverlo nel modo giusto?

Risposte

59 kaya3 Aug 21 2020 at 19:24

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.

20 Nathan Aug 21 2020 at 19:22

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
9 Carlos Aug 21 2020 at 19:18
  1. Scorri la stringa lettera per lettera
  2. 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.
  3. Se vedi il | carattere, non contarlo, salta e basta.
  4. 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))
1 JamesRushford Sep 18 2020 at 10:14

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