Подсчет букв в тексте на валлийском языке

Как посчитать буквы в Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogogoch?

print(len('Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'))

Говорит 58

Ну, если бы это было так просто, я бы не спрашивал тебя, не так ли ?!

Википедия говорит (https://en.wikipedia.org/wiki/Llanfairpwllgwyngyll#Placename_and_toponyname_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. Википедия ничего не говорит о том, что в имени есть буква ng, но она указана как один из диграфов на странице, которую я цитировал выше.

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

Таким образом, кажется, что «Llanfairpwllgwy ng yllgogerychwyrndrobwllllantysiliogogogoch» - одно из тех слов, где -ng- - это просто сочетание букв.

И, очевидно, компьютер не может это узнать. Так что мне придется предоставить ему дополнительную информацию, о которой говорит Википедия.

Так или иначе, я решил поискать в онлайн-словаре http://geiriadur.ac.uk/gpc/gpc.html, и вы увидите, что если вы посмотрите llongyfarch (пример из Википедии, в котором есть сопоставление букв), он отобразит его с вертикальной линией между n и g, но если вы посмотрите вверх, он этого не сделает.

снимок экрана из словаря (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) - снова считая |

Как я могу это исправить?


person Madarch    schedule 21.08.2020    source источник
comment
Поскольку вы пытаетесь измерить только одно слово, и вы знаете слово и его длину, почему бы просто не создать постоянную строку, содержащую строку, и константу int, содержащую длину строки, и покончить с этим? Не нужно делать это в коде, правда?   -  person raddevus    schedule 21.08.2020
comment
Я мало что знаю о питоне. после того, как вы сделаете count=count-1, не могли бы вы добавить index=index+1, чтобы пропустить следующую букву?   -  person rhavelka    schedule 21.08.2020
comment
Итак, я не знаю тонны о питоне, но я подумал, что у них должна быть какая-то концепция культуры для строк? В .NET, например, вы должны установить культуру своего приложения и, исходя из этого, по-разному обрабатывать определенные символы. Если идея здесь не в том, что вы пытаетесь реализовать это с нуля самостоятельно, игнорируйте этот комментарий.   -  person Max Young    schedule 21.08.2020
comment
Если бы это был C #, я мог бы предложить "ch dd ff ng ll ph rh th |".Split().ToList().ForEach(a => sb.Replace(a, a == "|" ? ".": "")); //sb is a stringbuilder - просто замените каждый из диграфов символом, которого нет в строке, и, наконец, замените | ничем; результирующая длина - это ваша строка. Не разработчик python, но должен работать тот же процесс, чтобы заменить двойные на одиночные ..   -  person Caius Jard    schedule 22.08.2020
comment
th и sh - это диграфы на английском языке, но я никогда не встречал никого, кто рассматривал бы эти отдельные буквы в смысле глифов. Вы спрашиваете о подсчете фонем, которые, как известно, неудобно сопоставляются с языками, написанными с помощью алфавитов. Обрыв слога, который вы определили, - всего лишь одна двусмысленность.   -  person Xophmeister    schedule 23.08.2020
comment
Понятно, что валлийский и английский действуют по-разному в этом отношении. Примером является то, что если вы просматриваете слова в алфавитном порядке по ссылке словаря, которую я опубликовал (используя ссылки на следующее слово и предыдущее слово - обратите внимание на ссылку вверху справа, чтобы установить интерфейс на английский), cywystlwr идет перед словами ch - потому что буква ch после c в алфавите.   -  person Madarch    schedule 24.08.2020


Ответы (4)


Как и многие другие проблемы со строками, это можно легко решить с помощью регулярного выражения.

>>> 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_] (из здесь) соответствует словесным символам, не являющимся цифрами или знаками подчеркивания, т. Е. Буквам, в том числе с диакритическими знаками. .

person kaya3    schedule 21.08.2020
comment
Имеет ли значение порядок условий? Будет ли иметь приоритет над буквой от a до z, поскольку она появляется первой? Более конкретно, это конкретная вещь для регулярного выражения или каждый язык будет иметь свою собственную реализацию? - person Max Young; 21.08.2020
comment
Если вы хотите, чтобы регулярное выражение обрабатывало исходный ввод: pattern = re.compile(r'ch|dd|ff|ll|ph|rh|th|[a-z]|(ng^yf)', flags=re.IGNORECASE) - person benjessop; 21.08.2020
comment
@MaxYoung Да, именно из-за порядка частей орграфы имеют приоритет над отдельными буквами; это обычно верно в каждом движке регулярных выражений, который я видел. В частности, в Python в документации указано как целевая строка сканируется, RE разделяются символом '|' пробуются слева направо, так что это указанное поведение, и на него можно безопасно полагаться. - person kaya3; 21.08.2020
comment
@ benjessop - разве ваш шаблон не дает тот же результат без последнего |(ng^yf)? - person DarrylG; 21.08.2020
comment
@ kaya3 спасибо Мне было просто любопытно, что я никогда раньше не рассматривал это, и это был первый сценарий, в котором я столкнулся, когда это действительно имело значение. - person Max Young; 22.08.2020
comment
Кажется, что ваш код не работает, например "Ynys Mô", который я считаю имеющим 6 букв, но ваш код возвращает 5. - person Jörg W Mittag; 22.08.2020
comment
@ JörgWMittag Исправлено. - person kaya3; 22.08.2020
comment
Еще одна проблема заключается в том, что валлийский язык использует несколько заимствованных слов / фраз из английского языка и не всегда меняет их написание на валлийское, поэтому вы не можете абсолютно рассчитывать на то, что диграфы являются диграфами ...: - | Ах, естественные языки такие забавные. :-) - person T.J. Crowder; 22.08.2020
comment
@benjessop, что это (ng^yf)? Может ли он когда-либо соответствовать чему-либо, когда ^ означает начало строки? - person ilkkachu; 22.08.2020
comment
Как регулярное выражение может отличить орграф от сопоставления? - person Dirk Lachowski; 26.08.2020
comment
@DirkLachowski Регулярное выражение, конечно, не может, но, согласно вопросу, входная строка будет иметь символ |, разделяющий две буквы, если они не являются орграфом. - person kaya3; 26.08.2020
comment
@ kaya3 А! Прочитал бы я вопрос внимательнее, я бы не задал глупого вопроса. Я как-то перепутал | с маленьким L. Спасибо за разъяснения. - person Dirk Lachowski; 27.08.2020

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

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
person Nathan    schedule 21.08.2020
comment
+1 за то, что он очень прост, я бы никогда не подумал просто токенизировать, из-за отсутствия лучших терминов, символы, которые сопряжены. У меня такое чувство, что мне придется применить это к алгоритму, над которым я работал, для обнаружения повторяющихся символов в японском тексте, но где дублирование правильное. Проблема, с которой я сталкиваюсь в японском языке, заключается в том, что, например, хахаха - это три одинаковых символа подряд, но теоретически это могут быть первые два символа, которые я говорю, а последний символ - частица. - person Max Young; 21.08.2020
comment
В этом случае он отлично работает. Если вы применяете этот метод к другим строкам, вам необходимо убедиться, что промежуточная переменная не содержит орграфов, которых нет в исходной строке. - person Eric Duminil; 23.08.2020

  1. Шаг за шагом по строке
  2. Если вы находитесь в индексе n и s [n: n + 2] является орграфом, добавьте или увеличьте словарь с орграфом в качестве ключа, а также увеличьте индекс на 1, чтобы вы не начинали со второго орграфа. персонаж. Если это не орграф, просто добавьте или увеличьте букву в слове и переходите к следующей букве.
  3. Если вы видите | персонаж, не считайте, просто пропустите.
  4. И не забывайте строчные буквы.

Когда вы увидите все буквы, цикл заканчивается, и вы добавляете все числа в dict.

Вот мой код, он работает на ваших трех примерах:

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))
person Carlos    schedule 21.08.2020

Вы можете использовать символ Combining Grapheme Joiner (+ 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-letter-counts.aspx

person James Rushford    schedule 18.09.2020