我有一个 .NET 应用程序,给定一个名词,我希望它正确地为该单词添加前缀“a”或“an”。我该怎么做?
在您认为答案是简单地检查第一个字母是否是元音之前,请考虑以下短语:
- 一个诚实的错误
- 一辆二手车
我有一个 .NET 应用程序,给定一个名词,我希望它正确地为该单词添加前缀“a”或“an”。我该怎么做?
在您认为答案是简单地检查第一个字母是否是元音之前,请考虑以下短语:
您可能没有比这更好的了 - 它肯定会击败大多数基于规则的系统。
编辑:我已经在 JS/C# 中实现了这个。您可以在浏览器中试用它,或者下载它使用的小型、可重复使用的 javascript 实现。.NET 实现打包AvsAn
在 nuget 上。这些实现很简单,因此如果需要,应该很容易移植到任何其他语言。
原来“规则”比我想象的要复杂得多:
...这只是强调基于规则的系统很难构建!
您需要使用例外列表。我不认为所有的例外都得到了很好的定义,因为它有时取决于说这个词的人的口音。
一种愚蠢的方法是向 Google 询问两种可能性(使用其中一种搜索 API)并使用最流行的一种:
或者:
因此“一个欧洲”和“一个诚实”是正确的版本。
如果您可以找到单词发音的单词拼写来源,例如:
"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 中,您可以使用它们来添加例外情况。
您必须手动实现并添加您想要的例外情况,例如,如果第一个字母是“H”,然后是“O”,如诚实、小时......以及相反的如欧洲、大学、使用......
由于“a”和“an”是由语音规则而不是拼写约定决定的,我可能会这样做:
你需要看看不定冠词的语法规则(英语语法中只有两个不定冠词——“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';
}
创建规则然后创建例外列表并使用它可能是最简单的。我不认为会有那么多。
伙计,我意识到这可能是一个已解决的论点,但我认为它可以比使用维基百科的临时语法规则更容易解决,它充其量只能派生白话语法。
似乎最好的解决方案是使用 a 或 an 触发基于音素的下一个单词的匹配,其中某些音素始终与“an”相关联,其余的属于“a”。
卡内基梅隆大学有一个很棒的在线工具来进行这些检查 - http://www.speech.cs.cmu.edu/cgi-bin/cmudict - 并且有 125k 单词和匹配的 39 个音素。插入一个词提供了整个音位集,其中只有第一个是重要的。
如果该词没有出现在字典中,例如“NSA”并且全部大写,则系统可以假设该词是首字母缩略词,并根据相同的原始规则集使用第一个字母来确定使用哪个不定冠词。
@Nathan Long:下载维基百科实际上并不是一个坏主意。不需要所有图像、视频和其他媒体。
我用php和javascript(!)编写了一个(糟糕的)程序来阅读整个瑞典维基百科(或者至少可以从关于数学的文章中找到的所有文章,这是我蜘蛛的开始。)
我在数据库中收集了所有单词和内部链接,并跟踪了每个单词的频率。我现在将它用作各种任务的单词数据库: * 查找可以从给定字母集(包括通配符)创建的所有单词 * 为瑞典语创建了一个简单的语法文件(所有不在数据库中的单词都被认为是不正确的)。
哦,下载整个 wiki 大约需要一周时间,我的笔记本电脑大部分时间都在运行,连接速度为 10Mbit。
当您使用它时,记录所有与英语不一致的事件,并查看其中一些是否是错误的。去修复它们并回馈社区。
请注意,正如 Grammar Girl 在她的情节A Versus An中指出的那样,美国方言和英国方言之间存在差异。
一种复杂情况是,英式和美式英语中的单词发音不同。例如,某种植物的单词在美式英语中发音为“erb”,在英式英语中发音为“herb”。在出现问题的极少数情况下,请使用您所在国家或大多数读者所期望的表格。
看看 Perl 的Lingua::EN::Inflect。见sub _indef_article
源代码。
我从Python移植了一个函数(最初来自 CPAN 包 Lingua-EN-Inflect),该函数正确确定 C# 中的元音,并将其发布为问题的答案,以编程方式确定是否用 a 或 an 描述对象?. 您可以在此处查看代码片段。
我会使用基于规则的算法尽可能多地覆盖,然后使用例外列表。如果你想变得花哨,你可以尝试从你的例外列表中确定一些新的“规则”。
我只是看起来像一组启发式方法。它需要更复杂一些,并回答一些我从未得到好的答案的问题,例如你如何处理缩写(“a RPM”或“an RPM”?我一直认为后者更有意义)。
在讨论如何处理英语单数前缀的语言库上进行了快速搜索,但如果你深入挖掘,你可能会找到一些东西。如果没有 - 你总是可以编写自己的变形库并获得世界声誉:-)。
我不认为您可以只填写一些样板文件,例如“a/an”作为一步涵盖所有内容。否则,您最终会出现假设错误,例如所有带有 'h' 的单词都由 'o' 得到 'an' 而不是 'a' 像 'home' - (一个家?)。基本上,你最终会包含英语语言的逻辑,或者偶尔会发现让你看起来很愚蠢的罕见情况。
检查单词是否以元音或辅音开头。“u”通常是辅音和元音(“yu”),因此出于您的目的属于辅音组。
字母“h”在法语和英语中使用的法语单词中代表 gottal stop(辅音)。您可以列出这些(实际上,包括“honor”、“honour”和“hour”可能就足够了)并将它们视为以元音开头(因为英语不识别声门塞音)。
还将“eu”视为辅音等。
这不是太难。
a 或 a 的选择取决于单词的发音方式。通过查看单词,您不一定能分辨出它的正确发音,例如行话或缩写等。其中一种方法是拥有支持音素的字典并使用与单词相关的音素信息来确定“a " 或 "an" 应使用。
我不能确定它是否有适当的信息来区分“a”和“an”,但普林斯顿的WordNet数据库正是为了类似任务而存在,所以我认为数据很可能在那里. 它有数万个单词和数十万个单词之间的关系(IIRC;我在网站上找不到当前的统计数据)。给它看看。它可以免费下载。
如何?什么时候呢?获取附有文章的名词。以特定的形式要求它。
询问文章中的名词。许多 MUD 代码库将项目存储为信息,包括:
关键字形式可能是“短剑生锈”。简称为“一把剑”。长形将是“一把生锈的短剑”。
您正在编写“a vs. an”Web 服务吗?退后一步,看看您是否可以在上游进一步攻击此泄漏。你可以建造一座水坝,但除非你阻止它流动,否则它最终会溢出。
确定这是多么重要,正如其他人所建议的那样,选择“快速但粗糙”或“昂贵但坚固”。
规则很简单。如果下一个单词以元音开头,则使用“an”,如果以辅音开头,则使用“a”。困难的是我们学校的元音和辅音分类不起作用。“honour”中的“h”是元音,而“hospital”中的“h”是辅音。
更糟糕的是,一些像“诚实”这样的词以元音或辅音开头,这取决于说它们的人。更糟糕的是,对于某些说话者来说,某些单词会根据周围的单词而变化。
问题仅取决于您要投入多少时间和精力。你可以在几分钟内用“aeiou”作为元音写一些东西,或者你可以花几个月的时间对目标受众进行语言分析。它们之间有大量的启发式方法,对某些说话者来说是正确的,对另一些人来说是错误的——但是因为不同的说话者对同一个词有不同的判断,所以无论你怎么做,都不可能一直都是对的它。
理想的方法是在网上找到可以给你答案的地方,动态查询它们并缓存答案。对于初学者,您可以用几百个单词来启动系统。
(我不知道有这样的在线资源,但如果有的话我不会感到惊讶。)
因此,无需下载所有互联网即可获得合理的解决方案。这是我所做的:
我记得 Google在这里发布了 Google Books N-Gram 频率的原始数据。所以我下载了“a_”和“an”的 2-gram 文件。如果我没记错的话,大约是 26 场演出。从那我产生了一个字符串列表,其中绝大多数是你所期望的相反文章(如果我们期望元音带一个“an”)。我能够存储的最终单词列表不到 7 KB。
我倾向于修改包含不定冠词的语句,而不是编写可能依赖于文化并且有许多例外的代码。例如,与其说“此客户想要住在单户住宅中”,不如说“此客户想要‘单户住宅’的住房类型。” 这样,不定冠词不依赖于变量——例如,“该客户想要‘公寓’的住房类型。”
我想综合一些给定的答案,并贡献我自己的解决方案。
让我们从一些基本的启发式开始:
从单词的第一个字母开始。
确定单词是否是首字母缩写词。
[A-Z][A-Z]+
)来解决。
希望这会有所帮助。我怀疑它会比任何单个选项占用更少的资源,因为其中大部分都可以通过简单的“等于”语句(例如word[0] == 'a'
)或正则表达式(例如[aioAIO]
)以及一些简单的语言学知识来解决以及英文字母名称的读音。如果该词不属于简单的情况,则使用其他回答者提供的更复杂的解决方案之一。
每当下一个单词不是元音时,您都使用“a”?只要有元音,你就用“an”吗?
话虽如此,你不能只做一个像“a\s[a,e,i,o,u].*”这样的正则表达式吗?然后将其替换为“an?”