Підрахуйте літери в тексті валлійською мовою


79

Як порахувати літери в Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch?

print(len('Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'))

Каже 58

Ну, якби це було так просто, я б не запитував вас, зараз би ?!

У Вікіпедії сказано ( https://en.wikipedia.org/wiki/Llanfairpwllgwyngyll#Placename_and_toponymy )

Довга форма імені - найдовша топонім у Сполученому Королівстві і одна з найдовших у світі - 58 символів (51 "буква", оскільки "ch" та "ll" є диграфами, і в Валлійська мова).

Тож я хочу порахувати це і отримати відповідь 51.

Окі докі.

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

Так, але це обман, очевидно, я хочу використовувати слово як вхід, а не список.

У Вікіпедії також сказано, що валицькими диграфами є ch, dd, ff, ng, ll, ph, rh, th

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

Тож ми йдемо. Складемо довжину, а потім знімемо подвійний відлік.

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)

Це забирає мене так далеко

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

Здається, я тоді відніс занадто багато. Я маю отримати 51. Зараз одна проблема полягає в тому, що llllвін знайшов 3 llс і зняв три замість двох. Отже, це потрібно буде виправити. (Не повинно перекриватися.)

І тоді є ще одна проблема. ng. У Вікіпедії нічого не сказано про те, що в назві є буква "нг", але вона вказана як один з диграфів на сторінці, яку я цитував вище.

Вікіпедія дає нам тут ще кілька підказок: "може знадобитися додаткова інформація, щоб відрізнити справжній диграф від зіставлення літер" . І це наводить приклад " llongyfarch ", де ng - це просто "зіставлення літер", і " llong ", де це диграф.

Отже, здається, що "Llanfairpwllgwy ng yllgogerychwyrndrobwllllantysiliogogogoch" - це одне з тих слів, де -ng- це лише "супровід букв".

І, очевидно, комп’ютер не може цього знати. Тож мені доведеться надати їй ту «додаткову інформацію», про яку говорить Вікіпедія.

Так чи інакше, я вирішив заглянути в Інтернет-словник http://geiriadur.ac.uk/gpc/gpc.html, і ви можете переконатися, що якщо ви подивитесь на llongyfarch (приклад з Вікіпедії, де є "зіставлення літер") він відображає його вертикальною лінією між n і g, але якщо ви шукаєте "llong", то це не робить.

скріншот зі словника (llongyfarch)

скріншот зі словника (llong)

Тож я вирішив, що нам потрібно зробити, це надати додаткову інформацію, ввівши |рядок введення, як це робиться у словнику, щоб алгоритм знав, що ngбіт - це насправді дві літери. Але, очевидно, я не хочу, щоб |саме це вважалося як лист.

Отже, я отримав ці дані:

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)

і досі цей список диграфів:

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

і правила будуть такими:

  1. ігнорувати регістр

  2. якщо ви бачите граграф, зарахуйте його як 1

  3. працюйте зліва направо, щоб llllбуло ll+ ll, а не l+ ll+l

  4. якщо ви бачите |не рахувати, але ви не можете повністю ігнорувати це, воно перестане ngбути диграфом

і я хочу, щоб це зарахували як 51 і зробили це з правильних причин, а не просто назустріч.

Зараз я отримую 51, але це збивається, тому що він зараховує |як букву (1 занадто висока), а потім знімає одну занадто багато з llll(1 занадто низька) - ПОМИЛКИ СКАСУВАТИ

Це стає llongправильно (3).

Це стає llon|gyfarchнеправильно (10) - відлік |знову

Як я можу це виправити правильно?


Оскільки ви намагаєтеся виміряти лише одне слово, і ви знаєте це слово та його довжину, чому б просто не створити константний рядок, який міститиме рядок, і константу int, щоб містити довжину рядка, і закінчити з ним? Не потрібно робити це в коді, так?
raddevus

Я не дуже багато знаю про python. після цього count=count-1, чи можете ви додати, index=index+1щоб пропустити наступний лист?
rhavelka

1
Тож я не знаю нічого про python, але я вважав, що вони повинні мати якесь поняття культури для струнних? Наприклад, у .NET ви встановите культуру свого додатка і виходячи з цього він буде по-різному ставитись до певних символів. Якщо тут не ідеться про те, що ви намагаєтесь реалізувати це з нуля самостійно, тоді проігноруйте цей коментар.
Макс Янг

Якби це був C #, я міг би запропонувати "ch dd ff ng ll ph rh th |".Split().ToList().ForEach(a => sb.Replace(a, a == "|" ? ".": "")); //sb is a stringbuilder- просто замініть кожен граграф символом, який не зустрічається в рядку, і нарешті замініть |нічим; отримана довжина - це ваш рядок. Не розробник python, але повинен спрацювати той самий процес, замінивши дубль на одного ...
Caius Jard

2
"th" та "sh" - це диграфи англійською мовою, але я ніколи не зустрічав нікого, хто вважає ці "одинарні літери", у сенсі гліфу. Ви запитуєте про підрахунок " фонем ", які, як відомо, незграбно відповідають мовам, написаним алфавітом. Розрив складу, який ви визначили, є лише однією неоднозначністю.
Xophmeister

Відповіді:


59

Як і багато проблем із рядками, це можна зробити простим способом за допомогою регулярного виразу.

>>> 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

Клас символів [^\W\d_]( звідси ) збігається зі словами-символами, які не є цифрами або підкресленнями, тобто буквами, в тому числі з діакритичними знаками.


Чи порядок умов там має значення? Чи буде пріоритет над проміжком через z, оскільки він з’являється першим? Більш конкретно, це те, що стосується регулярних виразів, чи кожна мова матиме свою реалізацію?
Макс Янг

Якщо ви хочете, щоб регулярний вираз pattern = re.compile(r'ch|dd|ff|ll|ph|rh|th|[a-z]|(ng^yf)', flags=re.IGNORECASE)
обробляв

3
@MaxYoung Так, порядок частин - це те, чому диграфи мають пріоритет над окремими літерами; це, як правило, вірно в кожному механізмі регулярних виразів, який я бачив. У Python, зокрема, у документах сказано: "Коли цільовий рядок сканується, РЕ розділяються символом" | " намагаються зліва направо " , тому на вказану поведінку і безпечно покладатися.
kaya3

7
Тоді проблема полягає в тому, що валлійська використовує кілька запозичених слів / фраз з англійської мови і не завжди змінює їх написання на валлійську, тому ви не можете абсолютно розраховувати на те, що диграфи є диграфами ...: - | Ах, природні мови - це така забава . :-)
TJ Crowder

2
@benjessop, про що це (ng^yf)? Чи може воно коли-небудь збігатися з чимось, коли ^означає початок рядка?
ilkkachu

20

Ви можете отримати довжину, замінивши всі подвійні літери на .(або будь-який інший символ, це ?буде чудово) і вимірявши довжину отриманого рядка (віднімаючи кількість |):

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

+1 за надзвичайну простоту, я б ніколи не подумав просто символізувати, через відсутність кращих термінів, символи, які є спряженими. У мене відчуття, що мені доведеться застосувати це до алгоритму, над яким я працював для виявлення повторюваних символів у японському тексті, але де дублювання є правильним. Проблема, з якою я стикаюся на японській мові, полягає в тому, що, наприклад, ха-ха-ха, це буде три однакові символи спиною до спини, але це теоретично може бути першими двома символами, які я вживаю, а останній символ - це частка.
Макс Янг

У цьому випадку це чудово працює. Якщо ви застосовуєте цей метод до інших рядків, вам потрібно переконатися, що посередницька змінна не містить граграфів, яких немає у вихідному рядку.
Ерік Думініл

9
  1. Покроково переходьте рядок за літерою
  2. Якщо ви знаходитесь в індексі n і і s [n: n + 2] є диграфом, додайте або збільште словник із діграфом як ключем, а також збільште індекс на 1, щоб не починати з другого диграфа характер. Якщо це не диграф, просто додайте або збільште літеру до дикту та перейдіть до наступної літери.
  3. Якщо ви бачите | символу, не рахуйте, просто пропустіть.
  4. І не забувайте про малі літери.

Коли ви побачили всі літери, цикл закінчується, і ви додаєте всі рахунки в дикті.

Ось мій код, він працює на твоїх трьох прикладах:

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

Ви можете використовувати комбінований символ графеми (+ u034F), щоб приєднати літери, а потім підрахувати кількість символів і забрати кількість цих столярів * 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

Уповноважений з валлійської мови також розглядає цю проблему тут: http://www.comisiynyddygymraeg.cymru/English/Part%203/10%20Locales%20alphabets%20and%20character%20sets/10.2%20Alphabets/Pages/10-2-1- Character-vs - count-letters.aspx

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.