用威尔士语计数文本中的字母


78

如何计算Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch中的字母?

print(len('Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch'))

说58

好吧,如果那是那么容易,我不会问你,现在可以吗?

维基百科说(https://en.wikipedia.org/wiki/Llanfairpwllgwyngyll#Placename_and_toponymy

名称的长格式是英国最长的地名,也是世界上最长的地名之一,共58个字符(因为“ ch”和“ ll”是二字,所以为51个“字母”,在英文字母中被视为单个字母)。威尔士语)。

所以我想算一下,得到答案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://zh.wikipedia.org/wiki/威尔士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 lls,然后取了3而不是2。因此,这将需要修复。(不得重叠。)

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

Wikipedia在这里为我们提供了更多线索:“可能需要其他信息来区分真正的有向图和字母并列”。并给出了一个示例“ llongyfarch ”,其中ng只是一个“字母并置”,而“ llong ”则是一个有向图。

因此,似乎'Llanfairpwllgwy ng yllgogerychwyrndrobwllllantysiliogogogoch'是其中-ng-只是“字母并置”的那些单词之一。

显然,计算机无法知道这一点。因此,我将不得不提供Wikipedia所说的“其他信息”。

因此,无论如何,我决定查看在线词典http://geiriadur.ac.uk/gpc/gpc.html,您会发现,如果您查找llongyfarch(来自Wikipedia的示例,其具有“字母并置”)它会在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)

还有这个有向图列表:

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

规则将是:

  1. 忽略大小写

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

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

  4. 如果您看到一个|不算数的书,但是您不能完全忽略它,那它就会停止ng成为有向图

我希望它能将其计为51,并且出于正确的原因而做,而不仅仅是fl幸。

现在我得到51,但由于它算作|一个字母(1太高)而使它起伏不定,然后它又由于(1太低)而脱落了一个太多的字母-ERRORS llllCANCEL OUT

它是llong正确的(3)。

llon|gyfarch出了错(10)-|再计算一次

如何正确解决问题?


由于您仅尝试测量一个单词,并且知道该单词及其长度,为什么不创建一个包含字符串的常量字符串和包含字符串长度的int常量并完成操作呢?无需在代码中执行此操作,对吧?
raddevus

我对python不太了解。完成后,您count=count-1可以添加index=index+1以跳过下一个字母吗?
rhavelka

1
所以我对python一无所知,但我认为它们必须对字符串具有某种文化概念?例如,在.NET中,您将设置应用程序的区域性,并根据此区域性对某些字符进行不同的处理。除非这里的想法是您要尝试从头开始实现此目标,否则请忽略此注释。
Max Young

如果是C#,我可以提供"ch dd ff ng ll ph rh th |".Split().ToList().ForEach(a => sb.Replace(a, a == "|" ? ".": "")); //sb is a stringbuilder-只需用字符串中不存在的char替换每个有向图,最后用no代替|;结果长度是您的字符串。没有一个python开发,而这一过程也应努力用单..取代双打,
凯厄斯Jard

2
“ th”和“ sh”是英文的二字组合,但从字形意义上讲,我从未遇到过任何认为这些“单字母”的人。您在问有关计数“音素”的问题,该音素笨拙地映射到用字母书写的语言。您已经确定的音节中断只是一个歧义。
Xophmeister

Answers:


58

就像许多与字符串有关的问题一样,这可以通过正则表达式以简单的方式完成。

>>> 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_](从此处开始)匹配不是数字或下划线的单词字符,即字母,包括带有变音符号的字符。


条件的顺序在那里重要吗?因为它会先出现,所以它会优先于a到z吗?更具体地说,是正则表达式特定的东西,还是每种语言都有其自己的实现?
Max Young

如果您想让正则表达式处理原点输入:pattern = re.compile(r'ch|dd|ff|ll|ph|rh|th|[a-z]|(ng^yf)', flags=re.IGNORECASE)
benjessop,

3
@MaxYoung是的,这些部分的顺序是为什么有向于图优先于单个字母;在我所见过的每个正则表达式引擎中,通常都是如此。具体来说,在Python中,文档“在扫描目标字符串时,RE用'|'分隔 从左到右尝试”,因此这是指定的行为,可以放心使用。
kaya3

7
然后是一个问题,威尔士人使用英语中的几个外来词/短语,并且并不总是将其拼写更改为威尔士语拼写,因此您不能绝对指望有向图是有向图...:-| 啊,自然语言真有趣。:-)
TJ Crowder

2
@benjessop,那是(ng^yf)什么?当^以字符串开头时,它可以匹配任何东西吗?
ilkkachu

19

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

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非常简单,我从来没有想过要对共轭字符进行分词,因为缺乏更好的术语。我有一种感觉,我必须将其应用于我一直在研究的算法中,该算法可用于检测日语文本中的重复字符,但是重复是正确的。我在日语中遇到的问题是,例如hahaha会是三个背对背相同的字符,但是从理论上讲,这可能是我单词的前两个字符,最后一个字符是粒子。
Max Young

在这种情况下,它可以正常工作。如果将此方法应用于其他字符串,则需要确保中介变量不包含原始字符串中不存在的有向图。
埃里克·杜米尼尔

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.