在孟加拉语单词中查找音节的正则表达式

4
这里是代码:
BanglaAlphabet = {
    'Consonant'                   : '[\u0995-\u09B9\u09CE\u09DC-\u09DF]',
    'IndependantVowel'            : '[\u0985-\u0994]',
    'DependantVowel'              : '[\u09BE-\u09CC\u09D7]',
    'Nukta'                       : '[\u09BC]'
}
BanglaWordPattern = ur"""(
    ({DependantVowel}{Nukta}{Consonant}) |
    ({DependantVowel}{Consonant}) |
    {IndependantVowel} |
    {Consonant} |
)+""".format(**BanglaAlphabet)
BanglaWordPattern = re.compile(BanglaWordPattern, re.VERBOSE)

匹配是通过以下方式完成的:
re.match(BanglaWordPattern, w[::-1])

这是为了从右到左匹配有效的孟加拉词而设计的。

然而,它在匹配时也会匹配无效的单词,比如 োগাড় 和 িদগ。

可能出了什么问题?

编辑

在 @GarethRees 和 @ChrisMorgan 的多次更正建议下,我最终得到:

bangla_alphabet = dict(
    consonant         = u'[\u0995-\u09b9\u09ce\u09dc-\u09df]',
    independent_vowel = u'[\u0985-\u0994]',
    dependent_vowel   = u'[\u09be-\u09cc\u09d7]',
    dependent_sign    = u'[\u0981-\u0983\u09cd]',
    virama            = u'[\u09cd]'
)
bangla_word_pattern = re.compile(ur'''(?:
    {consonant}
    ({virama}{consonant})?
    ({virama}{consonant})?
    {dependent_vowel}?
    {dependent_sign}?
    |
    {independent_vowel}
    {dependent_sign}?
)+

匹配现在是这样的:
bangla_word_pattern.match(w)

这段代码不仅可以纠正错误,而且比以前涵盖了更多的字符和有效结构。
我很高兴地报告说它正在按预期工作。因此,这段代码现在作为验证孟加拉语单词语法的非常基本的正则表达式。
有几个特殊规则/异常没有实现。我将逐步研究并将它们添加到这个基本结构中。
许多''.format(**bangla_alphabet), re.VERBOSE)
匹配现在是:
xCodexBlockxPlacexHolderx
这段代码不仅可以纠正错误,而且比以前涵盖了更多的字符和有效结构。
我很高兴地报告说它正在按预期工作。因此,这段代码现在作为验证孟加拉语单词语法的非常基本的正则表达式。
有几个特殊规则/异常没有实现。我将逐步研究并将它们添加到这个基本结构中。

你可以将 ({virama}{consonant})? 中的 ( 改为 (?: 以提高性能。 - Chris Morgan
好的,我会做的。再次感谢。 - Velvet Ghost
2个回答

3

您的字符串কয়া由以下字符组成:

>>> import unicodedata
>>> map(unicodedata.name, u'কয়া')
['BENGALI LETTER KA', 'BENGALI LETTER YA', 'BENGALI SIGN NUKTA', 'BENGALI VOWEL SIGN AA']

您的正则表达式无法匹配U+09BC孟加拉符号NUKTA。

查看孟加拉代码图表,可能您错过了一些其他字符。


好的,针对您更新的问题,您犯了三个错误:

  1. BanglaAlphabet字典中的字符串缺少u(Unicode)标志。这意味着Unicode转义序列(例如\u0995)未被转换为Unicode字符。您只会得到反斜杠、字母和数字。

  2. BanglaWordPattern正则表达式末尾附近有一个竖线|,后面没有内容。这意味着整个正则表达式看起来像(stuff1|stuff2|stuff3|stuff4|)+。所以实际上有五种选择,最后一种是空的。空的正则表达式当然可以匹配任何内容。

  3. 您实际上并没有查看程序的结果以查看它实际匹配的内容。如果您编写m = re.match(BanglaWordPattern, w[::-1]); print m.group(0),您将看到实际匹配的是空字符串。

我认为以下也是错误,但您没有解释您尝试做什么,所以我不太确定:

  1. 您将匹配反转了,这是不必要的。如果您将模式翻转并向前匹配,它会更简单,更容易理解。

  2. 您在正则表达式中使用捕获括号。如果您不需要结果,请改用非捕获括号(?:...)

  3. 内部括号本来就是不必要的。

  4. 您没有将正则表达式的末尾锚定到单词边界或字符串的末尾。

我会写出类似于以下内容的代码:

import re

bangla_categories = dict(
    consonant         = u'[\u0995-\u09B9\u09CE\u09DC-\u09DF]',
    independent_vowel = u'[\u0985-\u0994]',
    dependent_vowel   = u'[\u09BE-\u09CC\u09D7]',
    nukta             = u'[\u09BC]',
)

bangla_word_re = re.compile(ur"""(?:
    {consonant}{nukta}{dependent_vowel} |
    {consonant}{dependent_vowel} |
    {independent_vowel} |
    {consonant}
)+(?:\b|$)""".format(**bangla_categories), re.VERBOSE)

但我也会看看您忽略的代码图表中的其他孟加拉标志。 U + 0981 孟加拉语标记CANDRABINDU和U + 0982 孟加拉语标记ANUSVARA(使元音带鼻音)如何? U + 09CD 孟加拉语标记VIRAMA(取消元音)呢?等等。


我不知道为什么有nukta字符。代码表上说它是用于“将字母扩展到新字母”的。问题是:当我将{DependantVowel}{Consonant}更改为{DependantVowel}{Nukta}{Consonant}时,所有东西都与正则表达式匹配 - 即使是无效的单词! - Velvet Ghost
维基百科表示,Nukta“通过应用于现有字符来表示其他语言的声音”。 - Gareth Rees
我已更新了原始帖子以反映目前的情况。谢谢。 - Velvet Ghost
我在原帖中添加了一个大的部分(标记为“EDIT”)。看一下,非常感谢! - Velvet Ghost

1

你的代码存在几个问题:

  • 由于你没有使用Unicode字符串,在正则表达式中包括了文字字符\u0995,等等。你需要包含实际的Unicode字符。

  • 你需要在正则表达式结尾处添加 $ 以匹配整个字符串。

  • 你在第一组中用了一个空字符串,这是有效的(通过在第一组后面使用管道符号来结束),但是由于缺乏$符号,所以无法工作。

  • 如Gareth所指出的那样,代码不完整。

还要注意,一旦你获得了编译后的正则表达式对象,你也可以使用 bengali_word_pattern.match(s) 而不是 re.match(bengali_word_pattern, s)

bengali_alphabet = {
    'consonant': u'[\u0995-\u09B9\u09CE\u09DC-\u09DF]',
    'independent_vowel': u'[\u0985-\u0994]',
    'dependent_vowel': u'[\u09BE-\u09CC\u09D7]',
    'nukta': u'\u09BC'
}

bengali_word_pattern = ur'''^(?:
    (?:{dependent_vowel}{nukta}{consonant}) |
    (?:{dependent_vowel}{consonant}) |
    {independent_vowel} |
    {consonant}
)+$'''.format(**bengali_alphabet)
bengali_word_pattern = re.compile(bengali_word_pattern, re.VERBOSE)

现在,

>>> bengali_word_pattern.match(u'বাংলা'[::-1])

这个不起作用是因为 "ং" 字符,U+0982;它不在你的任何范围内。不确定那一位属于哪个类别;如果我们只是把有问题的字符拿掉,它就能工作了。(谷歌翻译告诉我,结果的单词可以翻译成“手镯”——我不知道,我需要问我的姐姐;我几乎只会方便的日常用语,比如“偷鸡”。而且那个词的第一个音节也被忽略了。无论如何,这不是重点。)
>>> bengali_word_pattern.match(u'বালা')
<_sre.SRE_Match object at 0x7f00f5bf9620>

它也适用于“偷鸡贼”这个短语。

>>> [bengali_word_pattern.match(w[::-1]) for w in u'মুরগি চোর'.split()]
[<_sre.SRE_Match object at 0x7f00f5bf9620>, <_sre.SRE_Match object at 0x7f00f5bf97e8>]

对于这两个不完整单词的例子,它不会返回匹配结果:

>>> bengali_word_pattern.match(u'োগাড়'[::-1])
>>> bengali_word_pattern.match(u'িদগ'[::-1])

此时我也承认自己感到困惑,不明白为什么你要反向解析字符串;我认为正向解析更有意义(如果这个正则表达式能够正确工作,那么你就不需要使用[::-1]):

^(?:
    {consonant}
    (?:
        {nukta}?
        {dependent_vowel}
    )?
    |
    {independent_vowel}
)+$

在每个连写字母处,获取一个独立的元音或可能跟随一个依赖元音的辅音,它们之间可能有一个nukta。

我所做的其他修改:

  • 变量/项命名,以适应标准Python编码风格;
  • 用非匹配组(?:...)替换了匹配组(...)以提高性能(请参阅文档);
  • 更正了“dependent”的拼写;
  • 将“bangla”改为“bengali”,因为在英语中它是孟加拉语;当我说英语时,我更喜欢使用一种语言的标准英语名称,而不是本地语言的发音,如果必要的话,可以进行英式化——例如,法语而不是le français。另一方面,我确实意识到,孟加拉人经常被英语使用者称为Bangla。

我无法感谢你提供如此详细的答案。我现在正在尝试你所有的建议,并将在大约30分钟后再次评论。顺便说一句...方便的日常用语,比如“মুরগি চোর”?你知道这意味着“偷鸡贼”吗?:P - Velvet Ghost
是的,我知道。 (“它也适用于”鸡贼“短语。”) - Chris Morgan
我在原帖中添加了一个大的部分(标记为“EDIT”)。看一下,非常感谢! - Velvet Ghost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接