2010-12-29 16 views
10

私は、アプリケーションで出力して説明する必要がある名詞(ex "house"、 "exclamation point"、 "apple")のデータベースを持っています。 "a"や "an"を使用せずにアイテムを説明するのは難しいです。 "家は大です"、 "感嘆符は小です"など"a"または "an"でオブジェクトを記述するかどうかをプログラムで決定しますか?

機能はありますか?ライブラリ、またはハック私はAまたはANで任意の名詞を記述する方が適切かどうかをPHPで判断できますか?

+0

私は実際にPHPが肥大化していることを考え始めるかもしれないこれをしたPHPのコア機能があった場合。 – webbiedave

+0

文法的に、hで始まる単語(houseなど)は、aまたはan ...のいずれかになります。 (hは黙っている)正直な人、houndの犬(hは難しい)/ホテル、(ちょっと恥知らずな話し手による) –

+0

@webbiedave - これをしたphp core関数があれば、私は、PHPのコア開発者が英語以外の言語の存在を忘れてしまったと思っています。そして、次のトリックのために、フランス名詞の前にle、la、lesまたはl 'を付けるべきかどうかを特定する関数 –

答えて

6

適切な不定冠詞を決定することです。 Lingua::EN::Inflectは素晴らしい仕事をするPerlモジュールです。私は関連するコードを抽出し、それを下に貼り付けました。これは単なるケースといくつかの正規表現なので、PHPに移植するのは難しいことではありません。誰かが興味があれば、友人はそれをPython hereに移植しました。

# 2. INDEFINITE ARTICLES 

# THIS PATTERN MATCHES STRINGS OF CAPITALS STARTING WITH A "VOWEL-SOUND" 
# CONSONANT FOLLOWED BY ANOTHER CONSONANT, AND WHICH ARE NOT LIKELY 
# TO BE REAL WORDS (OH, ALL RIGHT THEN, IT'S JUST MAGIC!) 

my $A_abbrev = q{ 
(?! FJO | [HLMNS]Y. | RY[EO] | SQU 
    | (F[LR]? | [HL] | MN? | N | RH? | S[CHKLMNPTVW]? | X(YL)?) [AEIOU]) 
[FHLMNRSX][A-Z] 
}; 

# THIS PATTERN CODES THE BEGINNINGS OF ALL ENGLISH WORDS BEGINING WITH A 
# 'y' FOLLOWED BY A CONSONANT. ANY OTHER Y-CONSONANT PREFIX THEREFORE 
# IMPLIES AN ABBREVIATION. 

my $A_y_cons = 'y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)'; 

# EXCEPTIONS TO EXCEPTIONS 

my $A_explicit_an = enclose join '|', 
(
    "euler", 
    "hour(?!i)", "heir", "honest", "hono", 
); 

my $A_ordinal_an = enclose join '|', 
(
    "[aefhilmnorsx]-?th", 
); 

my $A_ordinal_a = enclose join '|', 
(
    "[bcdgjkpqtuvwyz]-?th", 
); 

sub A { 
    my ($str, $count) = @_; 
    my ($pre, $word, $post) = ($str =~ m/\A(\s*)(?:an?\s+)?(.+?)(\s*)\Z/i); 
    return $str unless $word; 
    my $result = _indef_article($word,$count); 
    return $pre.$result.$post; 
} 

sub AN { goto &A } 

sub _indef_article { 
    my ($word, $count) = @_; 

    $count = $persistent_count 
     if !defined($count) && defined($persistent_count); 

    return "$count $word" 
     if defined $count && $count!~/^($PL_count_one)$/io; 

    # HANDLE USER-DEFINED VARIANTS 

    my $value; 
    return "$value $word" 
     if defined($value = ud_match($word, @A_a_user_defined)); 

    # HANDLE ORDINAL FORMS 

    $word =~ /^($A_ordinal_a)/i   and return "a $word"; 
    $word =~ /^($A_ordinal_an)/i  and return "an $word"; 

    # HANDLE SPECIAL CASES 

    $word =~ /^($A_explicit_an)/i  and return "an $word"; 
    $word =~ /^[aefhilmnorsx]$/i  and return "an $word"; 
    $word =~ /^[bcdgjkpqtuvwyz]$/i  and return "a $word"; 


    # HANDLE ABBREVIATIONS 

    $word =~ /^($A_abbrev)/ox   and return "an $word"; 
    $word =~ /^[aefhilmnorsx][.-]/i  and return "an $word"; 
    $word =~ /^[a-z][.-]/i    and return "a $word"; 

    # HANDLE CONSONANTS 

    $word =~ /^[^aeiouy]/i    and return "a $word"; 

    # HANDLE SPECIAL VOWEL-FORMS 

    $word =~ /^e[uw]/i     and return "a $word"; 
    $word =~ /^onc?e\b/i    and return "a $word"; 
    $word =~ /^uni([^nmd]|mo)/i   and return "a $word"; 
    $word =~ /^ut[th]/i     and return "an $word"; 
    $word =~ /^u[bcfhjkqrst][aeiou]/i and return "a $word"; 

    # HANDLE SPECIAL CAPITALS 

    $word =~ /^U[NK][AIEO]?/   and return "a $word"; 

    # HANDLE VOWELS 

    $word =~ /^[aeiou]/i    and return "an $word"; 

    # HANDLE y... (BEFORE CERTAIN CONSONANTS IMPLIES (UNNATURALIZED) "i.." SOUND) 

    $word =~ /^($A_y_cons)/io   and return "an $word"; 

    # OTHERWISE, GUESS "a" 
    return "a $word"; 
} 
+0

これは完璧に見えます、私はかなりPHPに新しいので、移植は少しの冒険になります! – MarathonStudios

+0

これは役に立ちます!誰かがPHPに移植する時間を見つけたら、ここに投稿してください! –

+0

私はこれを数日後に移植し、元の質問に投稿します – MarathonStudios

0

母音を含む配列を作成します。確認している単語の最初の文字が母音配列に含まれているかどうかを確認します。略語を扱う場合を除いて動作します。

+2

またはサイレントhのを扱うときに、あなたはハードにそれらの例外をコード化することができます。 – Tesserex

+0

はい、 "an"を使用するルールは、単語が母音で始まるかどうかです。私は教師がそれらを交換可能に使用するために私に怒ってしまった後、gr3でこれを返すことを覚えています。 – mpen

+7

「宇宙」はどうですか? – infrared

0

ゼロから書くのはかなり簡単です。tbh。単語が母音で始まる場合、それは 'a'を取得します。子音で始まる場合、それは 'an'を取得します。プログラマチックに行うのは簡単です。もしあなたが何かの悩みがあるなら(例えば、BBCの英国スタイルの "歴史的な機会"を使うかもしれません)、あなたはそれらを個別に扱うことができます。

複数形ではなく、 'a'/'an'文法規則のみで、インフレクターを使用するような種類です。 CakePHPやRailsが、どのようにして境界条件を扱うかなど、概念のより徹底的な議論をどのように扱うのか調べてみましょう。例えば、「鹿」を複数形で使用することは望ましくありません。 「gooses」なので、「宇宙」や吸引された/吸引されていない「H」のようなあなた自身の縁のように、個々に処理する必要があります。

+4

単語が母音で始まるかどうかはちょっと複雑です。その言葉がどのように発音され、綴られていないかに基づいています。たとえば、「1時間」または「ユーザー」とは言わず、「1時間」または「ユーザー」とは言いません。 – mfonda

+0

Yers、それゆえ、「縁のケース」の警告。これらのエッジケースは、あなたが次の文字を分析するだけで、発音が長い母音を持つかどうかを判断する方法を考案できない限り、手動で入力する必要があります。それで幸運。 – hollsk

+0

あなたはそれを助けるためにsoundex関数を使うことができます。 – profitphp

0

このようなソリューションを探していたので、ありがとうございましたmarcog。ここでは、ポートへの試みがあなたの友人のPythonのバージョンです(おそらくありますので、私は、PythonやPerlを知っていないいくつかのミス):1ビット(コメント「//わからないこれが何をするか」の下に)あります

function indefinite_article($word) { 
    // Lowercase version of the word 
    $word_lower = strtolower($word); 

    // An 'an' word (specific start of words that should be preceeded by 'an') 
    $an_words = array('euler', 'heir', 'honest', 'hono'); 
    foreach($an_words as $an_word) { 
      if(substr($word_lower,0,strlen($an_word)) == $an_word) return "an"; 
    } 
    if(substr($word_lower,0,4) == "hour" and substr($word_lower,0,5) != "houri") return "an"; 

    // An 'an' letter (single letter word which should be preceeded by 'an') 
    $an_letters = array('a','e','f','h','i','l','m','n','o','r','s','x'); 
    if(strlen($word) == 1) { 
      if(in_array($word_lower,$an_letters)) return "an"; 
      else return "a"; 
    } 

    // Capital words which should likely by preceeded by 'an' 
    if(preg_match('/(?!FJO|[HLMNS]Y.|RY[EO]|SQU|(F[LR]?|[HL]|MN?|N|RH?|S[CHKLMNPTVW]?|X(YL)?)[AEIOU])[FHLMNRSX][A-Z]/', $word)) return "an"; 

    // Special cases where a word that begins with a vowel should be preceeded by 'a' 
    $regex_array = array('^e[uw]','^onc?e\b','^uni([^nmd]|mo)','^u[bcfhjkqrst][aeiou]'); 
    foreach($regex_array as $regex) { 
      if(preg_match('/'.$regex.'/',$word_lower)) return "a";   
    } 

    // Special capital words 
    if(preg_match('/^U[NK][AIEO]/',$word)) return "a"; 
    // Not sure what this does 
    else if($word == strtoupper($word)) { 
      $array = array('a','e','d','h','i','l','m','n','o','r','s','x'); 
      if(in_array($word_lower[0],$array)) return "an"; 
      else return "a"; 
    } 

    // Basic method of words that begin with a vowel being preceeded by 'an' 
    $vowels = array('a','e','i','o','u'); 
    if(in_array($word_lower[0],$vowels)) return "an"; 

    // Instances where y follwed by specific letters is preceeded by 'an' 
    if(preg_match('/^y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)/', $word_lower)) return "an"; 

    // Default to 'a' 
    return "a"; 
} 

こと私はそれが何をしたのか分からなかった。誰かがそれを理解できるなら、私は知ってうれしいです。

8

これはC#プロジェクトに必要なので、ここでは上記のPython codeのC#ポートです。ソースファイルにusing System.Text.RegularExpressions;を必ず含めてください。

private string GetIndefiniteArticle(string noun_phrase) 
{ 
    string word = null; 
    var m = Regex.Match(noun_phrase, @"\w+"); 
    if (m.Success) 
     word = m.Groups[0].Value; 
    else 
     return "an"; 

    var wordi = word.ToLower(); 
    foreach (string anword in new string[] { "euler", "heir", "honest", "hono" }) 
     if (wordi.StartsWith(anword)) 
      return "an"; 

    if (wordi.StartsWith("hour") && !wordi.StartsWith("houri")) 
     return "an"; 

    var char_list = new char[] { 'a', 'e', 'd', 'h', 'i', 'l', 'm', 'n', 'o', 'r', 's', 'x' }; 
    if (wordi.Length == 1) 
    { 
     if (wordi.IndexOfAny(char_list) == 0) 
      return "an"; 
     else 
      return "a"; 
    } 

    if (Regex.Match(word, "(?!FJO|[HLMNS]Y.|RY[EO]|SQU|(F[LR]?|[HL]|MN?|N|RH?|S[CHKLMNPTVW]?|X(YL)?)[AEIOU])[FHLMNRSX][A-Z]").Success) 
     return "an"; 

    foreach (string regex in new string[] { "^e[uw]", "^onc?e\b", "^uni([^nmd]|mo)", "^u[bcfhjkqrst][aeiou]" }) 
    { 
     if (Regex.IsMatch(wordi, regex)) 
      return "a"; 
    } 

    if (Regex.IsMatch(word, "^U[NK][AIEO]")) 
     return "a"; 
    else if (word == word.ToUpper()) 
    { 
     if (wordi.IndexOfAny(char_list) == 0) 
      return "an"; 
     else 
      return "a"; 
    } 

    if (wordi.IndexOfAny(new char[] { 'a', 'e', 'i', 'o', 'u' }) == 0) 
     return "an"; 

    if (Regex.IsMatch(wordi, "^y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)")) 
     return "an"; 

    return "a"; 
} 
+0

C#の実装を探しているなら、私はウィキペディアから抽出された実際の使用パターンを使用して、奇妙なコーナーケースでも処理するhttp://code.google.com/p/a-vs-an/を書きました。ナゲットのAvsAnです。 –

7

私はこのような解決方法も探していましたが、JavaScriptで探していました。だから私はJSにそれを移植され、あなたがチェックアウトすることができますここではgithubの中の実際のプロジェクトhttps://github.com/rigoneri/indefinite-article.js

は、コードスニペットです:

function indefinite_article(phrase) { 

    // Getting the first word 
    var match = /\w+/.exec(phrase); 
    if (match) 
     var word = match[0]; 
    else 
     return "an"; 

    var l_word = word.toLowerCase(); 
    // Specific start of words that should be preceeded by 'an' 
    var alt_cases = ["honest", "hour", "hono"]; 
    for (var i in alt_cases) { 
     if (l_word.indexOf(alt_cases[i]) == 0) 
      return "an"; 
    } 

    // Single letter word which should be preceeded by 'an' 
    if (l_word.length == 1) { 
     if ("aedhilmnorsx".indexOf(l_word) >= 0) 
      return "an"; 
     else 
      return "a"; 
    } 

    // Capital words which should likely be preceeded by 'an' 
    if (word.match(/(?!FJO|[HLMNS]Y.|RY[EO]|SQU|(F[LR]?|[HL]|MN?|N|RH?|S[CHKLMNPTVW]?|X(YL)?)[AEIOU])[FHLMNRSX][A-Z]/)) { 
     return "an"; 
    } 

    // Special cases where a word that begins with a vowel should be preceeded by 'a' 
    regexes = [/^e[uw]/, /^onc?e\b/, /^uni([^nmd]|mo)/, /^u[bcfhjkqrst][aeiou]/] 
    for (var i in regexes) { 
     if (l_word.match(regexes[i])) 
      return "a" 
    } 

    // Special capital words (UK, UN) 
    if (word.match(/^U[NK][AIEO]/)) { 
     return "a"; 
    } 
    else if (word == word.toUpperCase()) { 
     if ("aedhilmnorsx".indexOf(l_word[0]) >= 0) 
      return "an"; 
     else 
      return "a"; 
    } 

    // Basic method of words that begin with a vowel being preceeded by 'an' 
    if ("aeiou".indexOf(l_word[0]) >= 0) 
     return "an"; 

    // Instances where y follwed by specific letters is preceeded by 'an' 
    if (l_word.match(/^y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)/)) 
     return "an"; 

    return "a"; 
} 
+1

私は 'd'が "aedhilmnorsx"で削除されるべきだと思います。 – spencercooly

0

ルールベースのシステムの問題は、彼らがエッジケースと悪い扱うということですそして、それらは複雑であること。意思決定を実際のデータに基づいて行うことができれば、より良い結果が得られます。 this answerでは、ウィキペディアを使ってルックアップ辞書を構築し、そのような辞書を使って(非常に単純な)JavaScript実装にリンクする方法について説明します。

接頭辞辞書は頭字語と数字をかなりよく扱いますが、多少の努力をすればおそらくもっとうまくいくでしょう。

関連する問題