1

我正在尝试构建我的第一个重要的正则表达式(用于 Python),但正在苦苦挣扎。

让我们假设语言 X(不是英语)中的一个单词是一系列最小“结构”。每个“结构”可以是:

An independent vowel (basically one letter of the alphabet)
A consonant (one letter of the alphabet)
A consonant followed by a right-attaching vowel
A left-attaching vowel followed by a consonant
(Certain left-attaching vowels) followed by a consonant followed by (certain right-attaching vowels)

例如这个 3 个字符的单词:

<a consonant><a left-attaching vowel><an independent vowel>

不是一个有效的单词,并且应该匹配正则表达式,因为左连接元音的右侧没有辅音。

我知道所有的 Unicode 范围——辅音、独立元音、左连接元音等的 Unicode 范围。

这是我到目前为止所拥有的:

WordPattern = (
ur'('
ur'[\u0985-\u0994]|'
ur'[\u0995-\u09B9]|'
ur'[\u0995-\u09B9(\u09BE|[\u09C0-\u09C4])]|'
ur'[(\u09BF|\u09C7|\u09C8)\u0995-\u09B9]|'
ur'[(\u09BF|\u09C7|\u09C8)\u0995-\u09B9(\u09BE|[\u09C0-\u09C4])]'
ur')+'
)

它不工作。除了让它工作之外,我还有三个具体问题:

  • 我需要将正则表达式拆分为多行,否则代码会看起来很糟糕。我该怎么做呢?
  • 我想使用某种字符串替换/模板来“命名”Unicode范围,以提高代码可读性并防止多次输入Unicode范围。
  • (这似乎很困难)允许的最小“结构”列表将不得不在以后扩展。有没有办法在正则表达式中设置一种“循环”机制,以便它适用于列表中所有允许的结构?

任何帮助,将不胜感激。这对初学者来说似乎很复杂!

4

2 回答 2

4

对具有非平凡形态的语言进行形态分析的合适工具是“有限状态转换器”。您可以跟踪和使用一些健壮的实现(一个由 Xerox Parc 提供)。有一个具有 python 绑定(用作外部库)。去谷歌上查询。

FST 基于有限状态自动机,例如(纯)正则表达式,但它们绝不是替代品。它是复杂的机器,所以如果您的目标很简单(例如,为了连字而进行音节化),您可能想要寻找更简单的东西。例如,有一些机器学习算法可以“学习”连字符。如果您确实对形态分析感兴趣,则必须努力研究 FST。

现在对于您的算法,如果您真的只需要一个简单的实现:由于任何元音或辅音都可以是独立的,因此您的规则是模棱两可的:它们允许将“ab”解析为“ab”。这种模糊性意味着正则表达式方法可能永远不会起作用,但如果您将较长的正则表达式放在首位,您可能会得到更好的结果,因此当两者都适用时,它们会优先使用较短的正则表达式。但实际上您需要构建一个解析器(手动或使用模块)并逐步尝试不同的事情。它与您想象的相反:设置一个使用不同正则表达式的循环,并逐步“使用”字符串。

但是,在我看来,您所描述的本质上是音节化。音节化的近乎普遍的规则是这样的:一个音节由一个核心元音,加上语言规则允许的尽可能多的前面(“起始”)辅音,加上后面的任何不能属于下一个音节的辅音。该规则称为“最大化起始”,它的结果是更容易向后解析音节(从单词的末尾)。试试看。

PS。您可能知道这一点,但是如果您将以下内容作为脚本的第二行,您可以将孟加拉语嵌入到您的正则表达式中:

# -*- coding: utf-8 -*-
于 2012-04-16T13:55:17.127 回答
0
  • 我需要将正则表达式拆分为多行,否则代码会看起来很糟糕。我该怎么做呢?

编译正则表达式时使用该re.VERBOSE标志。

pattern = re.compile(r"""(
                            [\u0985-\u0994]  # comment to explain what this is
                          | [\u0995-\u09B9]
                          # etc.
                         )
                      """, re.VERBOSE)
  • 我想使用某种字符串替换/模板来“命名”Unicode范围

你可以从普通的 Python 字符串构造一个 RE:

>>> subpatterns = {"vowel": "[aeiou]", "consonant": "[^aeiou]"}
>>> "{consonant}{vowel}+{consonant}*".format(**subpatterns)
'[^aeiou][aeiou]+[^aeiou]*'
  • 允许的最小“结构”列表将在以后扩展。有没有办法在正则表达式中设置一种“循环”机制,以便它适用于列表中所有允许的结构?

我不确定我是否明白你的意思,但是......假设你有一个(未编译的)RE列表,比如,patterns那么你可以计算它们的联合

re.compile("(%s)" % "|".join(patterns))

以这种方式构造 RE 时要小心特殊字符,并re.escape在必要时使用。

于 2012-04-16T12:40:32.060 回答