如何正确地在单词前加上"a"和"an"?

102

我有一个.NET应用程序,根据一个名词,我希望它能正确地在单词前加上"a"或"an"。我该怎么做?

在您认为答案仅仅是检查第一个字母是否为元音字母之前,请考虑以下短语:

  • 一次诚实的错误(an honest mistake)
  • 一辆二手车(a used car)

4
还要考虑缩写可能会导致使用"a"或"an"时产生一些混淆,例如"an NHL",尽管字母的发音以元音开头,但如果缩写可以作为一个单词发音,就不需要使用"an",比如说"a NAS设备"或"a NASCAR活动"。 - JB King
5
请注意,在使用a或an时,取决于所使用的英语方言中特定的发音。Herb这个词在英式和美式发音中就是一个例子。 - Eric
12
@Eric: 的确,我最喜欢的这个例子(也很书呆子)是“SQL”。有些人说字母“SQL”,有些人发音像单词“sequel”。每种发音需要使用不同的"a"或"an"。例如,“a sequel statement”与“it's an S-Q-L statement”。 - Binary Worrier
更加困难的是,即使在同一种英语方言中,意见也可能不同!例如,官方(英国)英语告诉我们“an hotel”是正确的结构,但大多数人在日常交流中会使用“a hotel”。如果您写出一个准确的版本,对我们其他人来说将非常有用! - h4xxr
拼写检查是如何处理这个问题的?他们是否维护大量的例外列表? - Ayush
显示剩余2条评论
25个回答

150
  1. 下载维基百科
  2. 解压并编写一个快速过滤程序,只输出文章文本(下载通常以XML格式提供,以及非文章元数据)。
  3. 查找所有的...实例,并在后面的单词和它的所有前缀上建立索引(可以使用简单的后缀trie)。这应该是区分大小写的,并且你需要一个最大单词长度-15个字母?
  4. (可选)丢弃所有出现少于5次或"a"与"an"之间比例不到2/3的前缀(或其他阈值-在此处进行微调)。最好保留空前缀以避免边角情况。
  5. 您可以通过丢弃其父级共享相同的"a"或"an"注释的所有前缀来优化前缀数据库。
  6. 在确定是使用"A"还是"AN"时,找到最长匹配的前缀,并跟随其领导。如果您在步骤4中没有丢弃空前缀,则将始终存在匹配的前缀(即空前缀),否则您可能需要为完全不匹配的字符串制定特殊情况(这种输入应该非常罕见)。

你可能无法得到比这更好的结果-它肯定会击败大多数基于规则的系统。

编辑:我已经用JS/C#实现了这个。 您可以在浏览器中尝试它,或者下载它使用的小型、可重复使用的javascript实现。 .NET实现包是 AvsAn on nuget. 实现非常简单,所以如果需要,将其移植到任何其他语言都应该很容易。

事实证明,“规则”比我想像的要复杂得多:

  • 这是意料之外的结果,但却得到了一致的投票。
  • 这是一个诚实的决定,但是一棵金银花灌木。
  • 符号: 这是一个0800号码,或无限大的牛至。
  • 首字母缩写: 这是一个NASA的科学家,但是一个NSA的分析员; 一辆FIAT车,但是一个FAA的政策。

这只是强调基于规则的系统构建起来会很棘手!


28
考虑到维基百科下载解压后(目前)达到2.8TB,如果有人使用这种方法,请公开发布生成的数据,以便不必重复此过程。 - Nathan Long
12
这个回答并非完全认真,但我确实做过类似的事情。维基百科使用原始wikimarkup格式的.xml文件大约只有40GB(最新版本会稍微大一些),而不是2.8TB,这个文件是完整的,不需要下载扩展的.html版本或任何图片,也许那个版本才是2.8TB吧?无论如何,只要您对标记不是太挑剔,解析起来其实相当可行。 - Eamon Nerbonne
1
这是我能想到的最大、最新的自然语言数据集之一,而且很容易获取。当然,任何其他的数据源也可以,毕竟算法并不依赖于维基百科。你可以在http://home.nerbonne.org/A-vs-An/或者[我的博客](http://eamon.nerbonne.org/2013/04/a-vs-determine-appropriate-english.html)上尝试在线实现。 - Eamon Nerbonne
1
任何足够大的语法正确的英文语料库都可以。这个解决方案是自然语言处理专家所称的“分布式语义学”的一个非常特殊的案例。 - Chthonic Project
1
我对这个解决方案感到非常印象深刻。老实说,我认为它会比完整下载维基百科简单得多。干得好,先生。+1 - keeehlan
显示剩余5条评论

16

您需要使用一份异常列表。我认为并非所有的异常情况都被很好地定义了,因为它有时取决于发音者的口音。

一个愚蠢的方法是使用 Google 的两个可能性(使用其中一个搜索 API),然后使用最受欢迎的:

或者:

因此,“a europe”和“an honest”是正确的版本。


6
这实际上是被允许的使用方式,还是会被禁止?我记得通常这种使用方式都是不被看好的。 - Eamon Nerbonne
1
@Eamon:有趣的观点。如果应用程序记录了它先前搜索过的所有单词,那么每遇到一个新单词,它只需要搜索一次,这样是否仍然是对Google的可疑使用? - gnovice
2
除了明显的技术难点(像这样自动化地使用搜索引擎输出是不允许的,而且很快就会被阻止),这种方法并没有以正确的方式解决问题 - 最坏的情况下,它会重复常见的语法误用。 - Guss
6
最坏情况下呢?有一个相当有力的论点可以被提出,即自然语言系统应该致力于复制“常见误用”。请参阅戴维·福斯特·华莱士的《权威和美国用法》一文,收录于《考虑龙虾》一书中。有比Google更好的语料库可供使用,但那是另一个问题。 - Robert Rossney
2
“a hotel” 和 “a heroine” 对我来说都是正确的。我猜你的口音可能略带伦敦腔。不同的口音意味着对于某些单词并没有标准答案。 - rjmunro
显示剩余2条评论

15

如果你能找到一个单词拼写到发音的来源,例如:

"honest":"on-ist"
"horrible":"hawr-uh-buhl, hor-"
你可以根据拼音字符串的第一个字符来做决策。为了提高性能,你可以使用这种查找方法预先生成异常集,并在执行过程中使用这些更小的查找集代替原始集合。
编辑后添加:!!! - 我认为您可以使用此方法生成您的异常:http://www.speech.cs.cmu.edu/cgi-bin/cmudict。当然,并非所有单词都会在字典中,意味着并不是所有可能的异常都会出现在您的异常集中,但在这种情况下,您可以默认对于元音使用 a,对于辅音使用 an,或者使用其他更好的启发式方法。
(查看CMU字典时,我很高兴看到它包括国家和一些其他地方的专有名词 - 因此它将处理像“乌克兰人”、“美国今日报”的例子,“乌拉尔灵感画”)。
再次编辑以添加:CMU字典不包含常见缩略语,并且您需要担心以 s、f、l、m、n、u 和 x 开头的缩略语。但是有许多缩写列表,比如维基百科中的列表,您可以使用这些列表来添加到异常中。

3
每当听到 "hawr-uh-buhl" 这个词,我总忍不住笑出声来。 - IS4

9

您需要手动实现并添加所需的异常,例如如果第一个字母是'H',后跟'O',如'honest'、'hour'等,以及相反的单词如'europe'、'university'、'used'等。


1
是的,没错。我想我在那方面弄错了。它根本没有规则。 - Ahmad Farid

8

由于“a”和“an”是由语音规则而不是拼写约定确定的,因此我可能会像这样做:

  1. 如果单词的第一个字母是辅音 -> 使用“a”
  2. 如果单词的第一个字母是元音 -> 使用“an”
  3. rjumnro所说,请保留一份例外清单(如heart,x-ray,house)。

5
您需要了解英语语法中不定冠词的语法规则(英语语法中只有两种不定冠词 - "a"和"an")。您可能不认为这听起来正确,但是英语语法的规则非常明确:“a”和“an”是不定冠词。我们在以元音字母开头的单词(a、e、i、o、u)前使用不定冠词“an”,在以辅音字母开头的单词(其他字母)前使用不定冠词“a”。 请注意,这意味着元音声音而不是元音字母。例如,以无声"h"开头的单词,如"honour"或"heir"被视为元音字母,因此在它们前面加上"an",例如:"It is an honour to meet you"。以辅音字母开头的单词则前缀为"a" - 这就是为什么您说"a used car"而不是"an used car"的原因 - 因为 "used" 有一个 "yoose" 的发音而不是 "uhh" 的发音。所以,作为一个程序员,这些就是要遵循的规则。您只需要想出一种确定单词以何种声音开头的方法,而不是以何种字母开头。我已经看到了一些例子,比如 Jaimie Sirovich 在 PHP 中的这个例子
function aOrAn($next_word) 
{ 
    $_an = array('hour', 'honest', 'heir', 'heirloom'); 
    $_a = array('use', 'useless', 'user'); 
    $_vowels = array('a','e','i','o','u'); 

    $_endings = array('ly', 'ness', 'less', 'lessly', 'ing', 'ally', 'ially'); 
    $_endings_regex = implode('|', $_endings); 

    $tmp = preg_match('#(.*?)(-| |$)#', $next_word, $captures); 
    $the_word = trim($captures[1]); 
    //$the_word = Format::trimString(Utils::pregGet('#(.*?)(-| |$)#', $next_word, 1)); 

    $_an_regex = implode('|', $_an); 
    if (preg_match("#($_an_regex)($_endings_regex)#i", $the_word)) { 
        return 'an'; 
    } 

    $_a_regex = implode('|', $_a); 
    if (preg_match("#($_a_regex)($_endings_regex)#i", $the_word)) { 
        return 'a'; 
    } 

    if (in_array(strtolower($the_word{0}), $_vowels)) { 
        return 'an';     
    } 

    return 'a'; 
}

最简单的方法可能是先创建规则,然后创建一个例外列表并使用它。我不认为会有太多的例外情况。


4

伙计,我意识到这可能是一个已经解决的争论,但我认为可以比使用维基百科的临时语法规则更容易地解决,最多只能推导出方言语法。

最好的解决方案似乎是使用a或an来触发后面单词基于音素的匹配,其中某些音素总是与"an"相关联,而剩下的则属于"a"。

卡内基梅隆大学为此类检查提供了一个很棒的在线工具 - http://www.speech.cs.cmu.edu/cgi-bin/cmudict - 它包含125k个单词和39个匹配的音素。输入一个单词即可提供整个音素集合,其中只有第一个是重要的。

如果单词未出现在字典中,例如“NSA”并且全部大写,则系统可以假定该单词是一个首字母缩略词,并根据同一原始规则集使用第一个字母确定使用哪个不定冠词。


1
就资源经济而言,这是最佳答案,我不明白为什么这会比提出的更数据密集的方法表现得更差。 - Chthonic Project

3

@Nathan Long: 下载维基百科并不是一个坏主意。不需要所有的图片、视频和其他媒体。

我用php和javascript写了一个(较差的)程序,以读取整个瑞典维基百科(或至少可以从有关数学文章开始的所有文章)。我在数据库中收集了所有单词和内部链接,并跟踪每个单词的频率。我现在将其用作各种任务的单词数据库: * 查找可以从给定字母集合(包括通配符)创建的所有单词 * 为瑞典语创建了一个简单的语法文件(数据库中不存在的所有单词都被认为是不正确的)。

哦,而且使用我的笔记本电脑和10Mbit连接大约花费一周的时间来下载整个维基百科。

当你正在做这件事时,请记录所有与英语语言不一致的情况,并查看其中是否有些错误。进行修复并回馈社区。


2
请注意,正如语法女神在她的《A Versus An》一集中指出的那样,美式英语和英式英语之间存在差异。
其中一个复杂因素是单词在英式英语和美式英语中发音不同。例如,某种植物的名称在美式英语中发音为“erb”,而在英式英语中发音为“herb”。在这种罕见情况下,应该使用你所在国家或大多数读者预期的形式。

2

异常情况位于inflections.t文件中。在我看来,这个列表相当不完整。 - Jan Aagaard

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