计算威尔士语文本中的字母

Mad*_*rch 80 python letter counting

我如何计算 Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch 中的字母?

print(len('Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'))
Run Code Online (Sandbox Code Playgroud)

说 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
Run Code Online (Sandbox Code Playgroud)

是的,但那是作弊,显然我想使用这个词作为输入,而不是列表。

维基百科也说威尔士语的有向图是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)
Run Code Online (Sandbox Code Playgroud)

这让我走到这一步

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
Run Code Online (Sandbox Code Playgroud)

看来我当时减去的太多了。我应该得到 51。现在的一个问题是llll它找到了 3ll秒,并取下了三个而不是两个。所以这将需要修复。(不得重叠。)

然后还有另一个问题。的ng。维基百科没有说名称中有字母“ng”,但它被列为我上面引用的页面上的有向图之一。

维基百科在这里给了我们更多的线索:“可能需要额外的信息来区分真正的有向图和并列的字母”。它给出了“ llongyfarch ”的例子,其中ng只是一个“字母并列”,而“ llong ”是一个有向图。

因此,“Llanfairpwllgwy ng yllgogerychwyrndrobwllllantysiliogogogoch”似乎是其中 -ng- 只是“字母并列”的词之一。

显然,计算机无法知道这一点。所以我将不得不向它提供维基百科所说的“附加信息”。

所以无论如何,我决定查看在线词典http://geiriadur.ac.uk/gpc/gpc.html,如果您查找llongyfarch(维基百科中的“字母并列”示例),您就会看到这一点它以 n 和 g 之间的垂直线显示它,但如果您查找“llong”,则它不会这样做。

字典截图(llongyfarch)

字典截图(长)

所以我决定好我们需要做的是通过|像在字典中一样在输入字符串中放入 a 来提供附加信息,这样算法就知道该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)
Run Code Online (Sandbox Code Playgroud)

还有这个有向图列表:

['ch','dd','ff','ng','ll','ph','rh','th']
Run Code Online (Sandbox Code Playgroud)

规则将是:

  1. 忽略大小写

  2. 如果您看到有向图,则将其计为 1

  3. 从左到右工作,所以llllll+ ll,而不是l+ ll+l

  4. 如果你看到 a|不计算它,但你不能完全忽略它,它就不再ng是一个有向图

我希望它把它算作 51 并且出于正确的原因去做,而不仅仅是侥幸。

现在我得到了 51,但它很糟糕,因为它把它算作|一个字母(1 太高),然后它用llll(1 太低)减去了太多 - 错误取消

它正在变得llong正确(3)。

它越来越llon|gyfarch错(10) -计数|再次

我怎样才能以正确的方式修复它?

kay*_*ya3 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
Run Code Online (Sandbox Code Playgroud)

字符类[^\W\d_](来自此处)匹配不是数字或下划线的单词字符,即字母,包括带有变音符号的字符。

  • 然后还有一个问题,威尔士语使用了几个来自英语的借用词/短语,并且并不总是将它们的拼写更改为威尔士语拼写,所以你不能绝对指望二合字母是二合字母......:-| 啊,自然语言真是*有趣*。:-) (7认同)
  • @MaxYoung是的,各部分的顺序就是为什么二合字母优先于单个字母的原因;在我见过的每个正则表达式引擎中通常都是如此。具体来说,在 Python 中,[文档](https://docs.python.org/3/library/re.html#index-13) 说 *“扫描目标字符串时,RE 由 '|' 分隔 从左到右进行尝试”*,因此这是指定的行为并且可以安全依赖。 (3认同)
  • @benjessop,‘(ng^yf)’是关于什么的?当“^”表示字符串的开头时,它可以匹配任何内容吗? (2认同)

Nat*_*han 21

您可以通过将所有双字母替换为 a .(或任何其他字符,?都可以)并测量结果字符串的长度(减去 的数量|)来获得长度:

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
Run Code Online (Sandbox Code Playgroud)


Car*_*los 10

  1. 逐个字母地遍历字符串
  2. 如果您在索引 n 并且 s[n:n+2] 是一个有向图,请添加或增加一个以有向图为键的字典,并将索引也增加 1,这样您就不会从第二个有向图开始特点。如果它不是有向图,只需将字母添加或增加到 dict 并转到下一个字母。
  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))
Run Code Online (Sandbox Code Playgroud)