98

我有一个 .NET 应用程序,给定一个名词,我希望它正确地为该单词添加前缀“a”或“an”。我该怎么做?

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

  • 一个诚实的错误
  • 一辆二手车
4

25 回答 25

143
  1. 下载维基百科
  2. 解压并编写一个快速过滤程序,只输出文章文本(下载通常为 XML 格式,以及非文章元数据)。
  3. 查找 a(n).... 的所有实例,并为以下单词及其所有前缀创建索引(您可以为此使用简单的 suffixtrie)。这应该区分大小写,并且您需要最大字长 - 15 个字母?
  4. (可选)丢弃所有出现少于 5 次或“a”与“an”达到少于 2/3 多数的前缀(或其他一些阈值 - 在此处调整)。最好保留空前缀以避免极端情况。
  5. 您可以通过丢弃其父级共享相同“a”或“an”注释的所有前缀来优化前缀数据库。
  6. 在确定是使用“A”还是“AN”时,找到最长的匹配前缀,并遵循它的引导。如果您在第 4 步中没有丢弃空前缀,那么总会有一个匹配的前缀(即空前缀),否则您可能需要一个完全不匹配的字符串的特殊情况(这样的输入应该非常少见) .

您可能没有比这更好的了 - 它肯定会击败大多数基于规则的系统。

编辑:我已经在 J​​S/C# 中实现了这个。您可以在浏览器中试用它,或者下载它使用的小型、可重复使用的 javascript 实现。.NET 实现打包AvsAn在 nuget 上。这些实现很简单,因此如果需要,应该很容易移植到任何其他语言。

原来“规则”比我想象的要复杂得多:

  • 这是一个出乎意料的结果,但这是一个一致的投票
  • 这是一个诚实的决定,但金银花灌木
  • 符号:这是一个0800 数字,或牛至∞。
  • 首字母缩略词:它NASA 科学家,但NSA 分析师菲亚特汽车,但美国联邦航空局的政策

...这只是强调基于规则的系统很难构建!

于 2009-08-17T15:02:05.567 回答
15

您需要使用例外列表。我不认为所有的例外都得到了很好的定义,因为它有时取决于说这个词的人的口音。

一种愚蠢的方法是向 Google 询问两种可能性(使用其中一种搜索 API)并使用最流行的一种:

或者:

因此“一个欧洲”和“一个诚实”是正确的版本。

于 2009-08-17T14:40:41.857 回答
15

如果您可以找到单词发音的单词拼写来源,例如:

"honest":"on-ist"
"horrible":"hawr-uh-buhl, hor-"

您可以根据拼写发音字符串的第一个字符做出决定。为了性能,也许您可​​以使用这样的查找来预先生成异常集,并在执行期间使用那些较小的查找集。

编辑添加:

!!!- 我想你可以用它来生成你的例外: http ://www.speech.cs.cmu.edu/cgi-bin/cmudict

当然,并非所有内容都会出现在字典中 - 这意味着并非所有可能的异常都会出现在您的异常集中 - 但在这种情况下,您可以默认为元音/辅音使用 a 或使用其他一些更好的启发式方法。

(查看 CMU 词典,我很高兴看到它包含国家和其他地方的专有名词 - 所以它会处理诸如“乌克兰人”、“今日美国报”、“乌拉尔风格的绘画”等示例。)

再次编辑添加:CMU 字典不包含常见的首字母缩写词,您必须担心以 s、f、l、m、n、u 和 x 开头的那些。但是那里有很多首字母缩略词列表,例如在 Wikipedia 中,您可以使用它们来添加例外情况。

于 2009-08-17T14:53:05.190 回答
9

您必须手动实现并添加您想要的例外情况,例如,如果第一个字母是“H”,然后是“O”,如诚实、小时......以及相反的如欧洲、大学、使用......

于 2009-08-17T14:38:13.937 回答
8

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

  1. 如果单词的第一个字母是辅音 -> 'a'
  2. 如果单词的第一个字母是元音-> 'an'
  3. 正如rjumnro 所说,保留一份例外清单(心脏、X 射线、房屋)。
于 2009-08-17T14:48:22.017 回答
5

你需要看看不定冠词的语法规则(英语语法中只有两个不定冠词——“a”和“an)。你可能不同意这些听起来正确,但英语语法规则很清楚

“a 和 an 是不定冠词。我们在以元音开头的词(a、e、i、o、u)之前使用不定冠词 an,在以辅音开头的词之前使用不定冠词 a(所有其他字母)。”

注意这意味着元音而不是元音字母。例如,以不发音的“h”开头的单词,例如“honour”或“heir”被视为元音,因此以“an”开头 - 例如,“It is an Honor 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'; 
}

创建规则然后创建例外列表并使用它可能是最简单的。我不认为会有那么多。

于 2009-09-10T19:35:41.670 回答
4

伙计,我意识到这可能是一个已解决的论点,但我认为它可以比使用维基百科的临时语法规则更容易解决,它充其量只能派生白话语法。

似乎最好的解决方案是使用 a 或 an 触发基于音素的下一个单词的匹配,其中某些音素始终与“an”相关联,其余的属于“a”。

卡内基梅隆大学有一个很棒的在线工具来进行这些检查 - http://www.speech.cs.cmu.edu/cgi-bin/cmudict - 并且有 125k 单词和匹配的 39 个音素。插入一个词提供了整个音位集,其中只有第一个是重要的。

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

于 2013-04-03T15:24:10.833 回答
3

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

我用php和javascript(!)编写了一个(糟糕的)程序来阅读整个瑞典维基百科(或者至少可以从关于数学的文章中找到的所有文章,这是我蜘蛛的开始。)

我在数据库中收集了所有单词和内部链接,并跟踪了每个单词的频率。我现在将它用作各种任务的单词数据库: * 查找可以从给定字母集(包括通配符)创建的所有单词 * 为瑞典语创建了一个简单的语法文件(所有不在数据库中的单词都被认为是不正确的)。

哦,下载整个 wiki 大约需要一周时间,我的笔记本电脑大部分时间都在运行,连接速度为 10Mbit。

当您使用它时,记录所有与英语不一致的事件,并查看其中一些是否是错误的。去修复它们并回馈社区。

于 2009-08-17T19:47:24.013 回答
2

请注意,正如 Grammar Girl 在她的情节A Versus An中指出的那样,美国方言和英国方言之间存在差异。

一种复杂情况是,英式和美式英语中的单词发音不同。例如,某种植物的单词在美式英语中发音为“erb”,在英式英语中发音为“herb”。在出现问题的极少数情况下,请使用您所在国家或大多数读者所期望的表格。

于 2009-08-17T14:48:50.923 回答
2

看看 Perl 的Lingua::EN::Inflect。见sub _indef_article源代码。

于 2009-08-17T17:03:32.937 回答
2

我从Python移植了一个函数(最初来自 CPAN 包 Lingua-EN-Inflect),该函数正确确定 C# 中的元音,并将其发布为问题的答案,以编程方式确定是否用 a 或 an 描述对象?. 您可以在此处查看代码片段。

于 2011-11-08T01:10:25.283 回答
1

你能得到一本英语词典,里面有我们的常规字母表和国际音标字母表中的单词吗?

再用拼音来判别词的首音,究竟“a”还是“an”合适?

不确定这是否真的比统计维基百科方法更容易(或有趣)。

于 2010-09-21T16:30:14.370 回答
0

我会使用基于规则的算法尽可能多地覆盖,然后使用例外列表。如果你想变得花哨,你可以尝试从你的例外列表中确定一些新的“规则”。

于 2009-08-17T14:43:48.357 回答
0

我只是看起来像一组启发式方法。它需要更复杂一些,并回答一些我从未得到好的答案的问题,例如你如何处理缩写(“a RPM”或“an RPM”?我一直认为后者更有意义)。

在讨论如何处理英语单数前缀的语言库上进行了快速搜索,但如果你深入挖掘,你可能会找到一些东西。如果没有 - 你总是可以编写自己的变形库并获得世界声誉:-)。

于 2009-08-17T14:44:02.600 回答
0

我不认为您可以只填写一些样板文件,例如“a/an”作为一步涵盖所有内容。否则,您最终会出现假设错误,例如所有带有 'h' 的单词都由 'o' 得到 'an' 而不是 'a' 像 'home' - (一个家?)。基本上,你最终会包含英语语言的逻辑,或者偶尔会发现让你看起来很愚蠢的罕见情况。

于 2009-08-17T14:45:39.180 回答
0

检查单词是否以元音或辅音开头。“u”通常是辅音和元音(“yu”),因此出于您的目的属于辅音组。

字母“h”在法语和英语中使用的法语单词中代表 gottal stop(辅音)。您可以列出这些(实际上,包括“honor”、“honour”和“hour”可能就足够了)并将它们视为以元音开头(因为英语不识别声门塞音)。

还将“eu”视为辅音等。

这不是太难。

于 2009-08-17T14:47:33.810 回答
0

a 或 a 的选择取决于单词的发音方式。通过查看单词,您不一定能分辨出它的正确发音,例如行话或缩写等。其中一种方法是拥有支持音素的字典并使用与单词相关的音素信息来确定“a " 或 "an" 应使用。

于 2009-08-17T15:00:27.020 回答
0

我不能确定它是否有适当的信息来区分“a”和“an”,但普林斯顿的WordNet数据库正是为了类似任务而存在,所以我认为数据很可能在那里. 它有数万个单词和数十万个单词之间的关系(IIRC;我在网站上找不到当前的统计数据)。给它看看。它可以免费下载。

于 2009-08-17T16:11:05.523 回答
0

如何?什么时候呢?获取附有文章的名词。以特定的形式要求它。

询问文章中的名词。许多 MUD 代码库将项目存储为信息,包括:

  • 一个或多个关键字
  • 一个简短的表格
  • 长表格

关键字形式可能是“短剑生锈”。简称为“一把剑”。长形将是“一把生锈的短剑”。

您正在编写“a vs. an”Web 服务吗?退后一步,看看您是否可以在上游进一步攻击此泄漏。你可以建造一座水坝,但除非你阻止它流动,否则它最终会溢出。

确定这是多么重要,正如其他人所建议的那样,选择“快速但粗糙”或“昂贵但坚固”。

于 2009-08-17T19:08:20.003 回答
0

规则很简单。如果下一个单词以元音开头,则使用“an”,如果以辅音开头,则使用“a”。困难的是我们学校的元音和辅音分类不起作用。“honour”中的“h”是元音,而“hospital”中的“h”是辅音。

更糟糕的是,一些像“诚实”这样的词以元音或辅音开头,这取决于说它们的人。更糟糕的是,对于某些说话者来说,某些单词会根据周围的单词而变化。

问题仅取决于您要投入多少时间和精力。你可以在几分钟内用“aeiou”作为元音写一些东西,或者你可以花几个月的时间对目标受众进行语言分析。它们之间有大量的启发式方法,对某些说话者来说是正确的,对另一些人来说是错误的——但是因为不同的说话者对同一个词有不同的判断,所以无论你怎么做,都不可能一直都是对的它。

于 2009-09-10T18:57:28.987 回答
0

理想的方法是在网上找到可以给你答案的地方,动态查询它们并缓存答案。对于初学者,您可以用几百个单词来启动系统。

(我不知道有这样的在线资源,但如果有的话我不会感到惊讶。)

于 2011-11-08T01:13:54.733 回答
0

因此,无需下载所有互联网即可获得合理的解决方案。这是我所做的:

我记得 Google在这里发布了 Google Books N-Gram 频率的原始数据。所以我下载了“a_”和“an”的 2-gram 文件。如果我没记错的话,大约是 26 场演出。从那我产生了一个字符串列表,其中绝大多数是你所期望的相反文章(如果我们期望元音带一个“an”)。我能够存储的最终单词列表不到 7 KB。

于 2014-10-11T04:34:05.700 回答
0

我倾向于修改包含不定冠词的语句,而不是编写可能依赖于文化并且有许多例外的代码。例如,与其说“此客户想要住在单户住宅中”,不如说“此客户想要‘单户住宅’的住房类型。” 这样,不定冠词不依赖于变量——例如,“该客户想要‘公寓’的住房类型。”

于 2021-07-30T14:26:25.343 回答
0

我想综合一些给定的答案,并贡献我自己的解决方案。

让我们从一些基本的启发式开始:

  1. 从单词的第一个字母开始。

    • 如果它以“a”、“i”或“o”开头,则使用“an”。据我所知,这些字母总是以实际元音开头。
    • 如果它以“b”、“c”、“d”、“g”、“k”、“p”、“q”、“t”、“v”、“w”或“z”开头,那么它保证是一个辅音,并且像辅音一样发音。
    • 如果它以“f”、“l”、“m”、“n”、“r”、“s”或“x”开头,它可以用元音发音,但前提是它是首字母缩略词。否则,它保证发音为辅音。
    • 如果它以“u”或“h”、“j”或“y”开头,则属于极端情况。
  2. 确定单词是否是首字母缩写词。

  • 如果单词是首字母缩略词,则假定它包含多个连续的大写字母,或包含句点。这可以通过一个简单的正则表达式(例如[A-Z][A-Z]+)来解决。
    • 如果单词是首字母缩略词,则在进行第 3 步之前,首先将其转换为更“类似单词”的形式(即,不要全部大写,不包含句点)。如果它不是首字母缩略词,请返回参考步骤 1 中的信息。
  1. 使用字典!
    • 如果该词在本词典中,并且以“a”、“e”、“i”、“o”或“u”开头,则它以元音开头。否则,它是一个辅音。
    • 维基词典和维基百科使用国际音标来表示单词的发音。如果单词以其中一个字母开头,则它以元音开头。

希望这会有所帮助。我怀疑它会比任何单个选项占用更少的资源,因为其中大部分都可以通过简单的“等于”语句(例如word[0] == 'a')或正则表达式(例如[aioAIO])以及一些简单的语言学知识来解决以及英文字母名称的读音。如果该词不属于简单的情况,则使用其他回答者提供的更复杂的解决方案之一。

于 2021-08-04T02:29:33.900 回答
-2

每当下一个单词不是元音时,您都使用“a”?只要有元音,你就用“an”吗?

话虽如此,你不能只做一个像“a\s[a,e,i,o,u].*”这样的正则表达式吗?然后将其替换为“an?”

于 2009-08-17T18:10:39.777 回答