2009-04-28 6 views
16

Я готовил имена таблиц для ORM, и я хочу превратить множественные имена таблиц в имена единых сущностей. Моя единственная проблема - найти алгоритм, который делает это надежно. Вот что я делаю прямо сейчас:Как включить слова множественного числа?

  1. Если слово заканчивается -ях, я заменяю окончание с -y
  2. Если слово заканчивается -es, я удалю это окончание. Это не всегда работает, однако - к примеру, он заменяет Типы с Typ
  3. В противном случае, я просто удалить задний -s

Кто-нибудь знает лучшего алгоритма?

+5

Я давно отказался от множественных имен таблиц и использовал уникальные имена для таблиц, которые меня спасают при вводе! –

+6

Все ваши правила имеют тривиальные случаи, когда они потерпят неудачу: «Торты», «Деревья», «Автобус». Конечно, есть и другие. Единственный ответ - (как говорит Тал Прессман), что вы имеете дело с естественным языком, где исключения являются правилом. – bignose

+0

.NET Inflector отлично подходит, вы можете определить правила, исключения, необычные плюрализации, не учетные записи, такие как рыба и овца и т. Д. И т. Д. Великая библиотека – BenAlabaster

ответ

21

Все это общие правила (и хорошие), но английский язык не является языком для слабонервных :-).

Мое предпочтение было бы иметь механизм трансформации вместе с набором преобразований (на удивление достаточно) для выполнения фактической работы.

Вы должны были выполнить преобразования (от определенного к общему) и, когда совпадение было найдено, применить преобразование к слову.

Регулярные выражения были бы идеальным подходом к этому из-за их выразительности. Набор примера правила:

1. If the word is fish, return fish. 
2. If the word is sheep, return sheep. 
3. If the word is "radii", return "radius". 
4. If the word is "types", return "type". 
5. If the word ends in "ii", replace that "ii" with "us" (octopii,virii). 
    : : : : : 
97. If a word ends with -ies, I replace the ending with -y 
98. If a word ends with -es, I remove this ending. 
99. Otherwise, I just remove the trailing -s. 

Обратите внимание, что более ранняя версия правил, возможно, не имела начальное число 4. Тем не менее, когда мы обнаружили проблему с «типами» трансформируется в «станд» на 98, мы тогда создал преобразование с более высоким приоритетом на 4, чтобы удовлетворить это.

Вам будет необходимо обновить эту таблицу преобразований, поскольку вы найдете все те чудесные исключения, которые породил английский язык.


Другая возможность - не тратить свое время на общее правило. Поскольку имена таблиц будут относительно ограниченными, просто создайте другую таблицу (или некоторую структуру данных) под названием singulars, которая отображает все соответствующие имена таблиц (employees) на имена уникальных объектов (employee).

Затем каждый раз, когда таблица добавляется, добавьте запись в таблицу уникальных чисел, чтобы вы могли ее разделить.

+0

хороший практический пример. – thomasrutter

+0

Ох, мне это нравится. это так downprioritizes (это новое слово) мои случаи, что я чувствую себя немного смущен. Хорошо. Дело принято. будет работать с исключениями, а не с правилами. –

+0

Регулярные выражения только на самом деле требуют от вас частичного пути, вам нужно создать класс, который позволит вам определить основные правила, исключения, несчетные записи, необычные варианты и множество других вариантов - некоторые используют латинский язык для плюрализации, некоторые используют греческую, это сложный предмет. – BenAlabaster

0

Я думаю, вам нужно использовать список для перевода множественного числа в единственное для некоторых специальных слов (в вашем примере Types-> Type).

Я думаю, вы могли бы взглянуть на исходный код CakePHP (вы можете начать поиск here). Они используют такой алгоритм для своих табличных имен и имен полей для автоматического объединения таблиц.


[Edit:] Здесь у вас есть несколько научных работ, чтобы прочитать о "Plural inflection in English"

8

Проблема в том, что основано на общих правилах, но английский имеет (образно) миллиард исключений ... Что вас делать со словами «рыба» или «гуси»?

Кроме того, правила заключаются в том, как превращать сингулярные существительные в множественные числа. Обратное отображение необязательно (см. «Халявы»).

+1

Я не думаю, что вы понимаете, насколько велик миллиард :-) Или вы были образным? [Это на самом деле баг-медведь, люди, которые говорят «буквально миллиард», когда они действительно означают образно]. – paxdiablo

+1

Ну, я не сказал «буквально», теперь я? : p Тем не менее, если это вас беспокоит так много ... –

+2

халява? (15 символов) –

0

Я уверен, что вы можете google найти множество библиотек, которые это делают.

Но если вам нравится кодирование, вы можете попробовать обратный процесс: начать с сингулярных слов словаря (скачать бесплатные, используемые aspell или что-то еще), использовать правило плюрализации; собирать сопоставления и переключать направление. Для «типа» вы бы разделили на «типы», и обратное отображение будет работать, как ожидалось. Хотя здесь есть исключения, немного легче надежно плюрализировать вещи. Я сделал это некоторое время назад (в середине 90-х ... :-)), для онлайн-игры (MUD), где были описаны описания для нескольких идентичных элементов, и была необходима автоматическая плюрализация.

Также: учитывая, что это конечное количество таблиц, вы можете просто использовать простейший алгоритм, получить исходный вывод, наблюдать за ним и исправить ошибки вручную. :-)

6

Эндрю Петерс имеет класс Inflector.NET, который предлагает множественные и единственные методы множественного числа. Как указал Тал, ни один алгоритм не является непогрешимым, но это покрывает приличное количество нерегулярных английских существительных.

+0

Я использовал это, и это здорово ... Я немного расширил его. Есть много примеров в сети необычной плюрализации, чтобы добавить к базовой версии, которую вы можете получить в Интернете. – BenAlabaster

+0

Inflector.NET - отличное решение этой проблемы. Если ссылка мертва выше, то вот ссылка github вместо https://github.com/srkirkland/Inflector – danielrbradley

3

Смотрите также this answer, который рекомендует использовать Морфу (или изучение алгоритма позади него).

Если вы знаете, что слова, которые вы хотите lemmatize, являются множественными существительными, тогда вы можете пометить их NNS, чтобы получить более точный результат.

Пример ввода:

$ cat test.txt 
Types_NNS 
Pies_NNS 
Trees_NNS 
Buses_NNS 
Radii_NNS 
Communities_NNS 
Sheep_NNS 
Fish_NNS 

Выходной пример:

$ cat test.txt | ./morpha -c 
Type 
Pie 
Tree 
Bus 
Radius 
Community 
Sheep 
Fish 
1

Как улучшение, вы можете использовать правила, которые генерируют множество возможностей, а затем посмотреть результаты в словаре отсеять невозможные варианты ,

Например, замените -ies на -y и -ie. Пироги становятся Py и пирогом. Только один из них находится в словаре, поэтому выберите его.

Возможно, вы даже можете найти словарь с информацией о частоте и выбрать наиболее распространенное слово, которое вы создаете.

Если вы комбинируете это с упорядоченным списком правил, который охватывает несколько исключений, вы можете получить довольно хорошую точность.

-1

В проекте uNnAddIns есть хороший implementation of an inflector, который даже реализует экспериментальный испанский инфлектор. Идею поймали из Rails Inflector module.

Его можно использовать и для других вещей, таких как преобразование из CamelCase в обычный текст и другие полезные свойства и, например, создание дружественных URL-адресов браузера из заголовков.

0

Я собираюсь попробовать этот MorphAdorner: http://morphadorner.northwestern.edu/morphadorner/download/ (Java). Это набор различных инструментов обработки NLP, и вы можете протестировать их через онлайн-примеры. Для вашей проблемы (это также моя проблема) есть инструмент Pluralizer: http://morphadorner.northwestern.edu/morphadorner/pluralizer/example/

+0

было бы неплохо, если бы он мог преобразовать множественное число обратно в одно имя объекта. или, может быть, я что-то пропустил? :) – trillions

1

Возможно, вам это нужно, это хорошо работает, если вы знаете, как использовать PHP-скрипт. Он может превращать множественные слова в отдельные слова и поворачивать единичные слова для множественных слов тоже.

class BaseInflector 
{ 
    /** 
    * @var array the rules for converting a word into its plural form. 
    * The keys are the regular expressions and the values are the corresponding replacements. 
    */ 
    public static $plurals = [ 
     '/([nrlm]ese|deer|fish|sheep|measles|ois|pox|media)$/i' => '\1', 
     '/^(sea[- ]bass)$/i' => '\1', 
     '/(m)ove$/i' => '\1oves', 
     '/(f)oot$/i' => '\1eet', 
     '/(h)uman$/i' => '\1umans', 
     '/(s)tatus$/i' => '\1tatuses', 
     '/(s)taff$/i' => '\1taff', 
     '/(t)ooth$/i' => '\1eeth', 
     '/(quiz)$/i' => '\1zes', 
     '/^(ox)$/i' => '\1\2en', 
     '/([m|l])ouse$/i' => '\1ice', 
     '/(matr|vert|ind)(ix|ex)$/i' => '\1ices', 
     '/(x|ch|ss|sh)$/i' => '\1es', 
     '/([^aeiouy]|qu)y$/i' => '\1ies', 
     '/(hive)$/i' => '\1s', 
     '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', 
     '/sis$/i' => 'ses', 
     '/([ti])um$/i' => '\1a', 
     '/(p)erson$/i' => '\1eople', 
     '/(m)an$/i' => '\1en', 
     '/(c)hild$/i' => '\1hildren', 
     '/(buffal|tomat|potat|ech|her|vet)o$/i' => '\1oes', 
     '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i', 
     '/us$/i' => 'uses', 
     '/(alias)$/i' => '\1es', 
     '/(ax|cris|test)is$/i' => '\1es', 
     '/s$/' => 's', 
     '/^$/' => '', 
     '/$/' => 's', 
    ]; 
    /** 
    * @var array the rules for converting a word into its singular form. 
    * The keys are the regular expressions and the values are the corresponding replacements. 
    */ 
    public static $singulars = [ 
     '/([nrlm]ese|deer|fish|sheep|measles|ois|pox|media|ss)$/i' => '\1', 
     '/^(sea[- ]bass)$/i' => '\1', 
     '/(s)tatuses$/i' => '\1tatus', 
     '/(f)eet$/i' => '\1oot', 
     '/(t)eeth$/i' => '\1ooth', 
     '/^(.*)(menu)s$/i' => '\1\2', 
     '/(quiz)zes$/i' => '\\1', 
     '/(matr)ices$/i' => '\1ix', 
     '/(vert|ind)ices$/i' => '\1ex', 
     '/^(ox)en/i' => '\1', 
     '/(alias)(es)*$/i' => '\1', 
     '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us', 
     '/([ftw]ax)es/i' => '\1', 
     '/(cris|ax|test)es$/i' => '\1is', 
     '/(shoe|slave)s$/i' => '\1', 
     '/(o)es$/i' => '\1', 
     '/ouses$/' => 'ouse', 
     '/([^a])uses$/' => '\1us', 
     '/([m|l])ice$/i' => '\1ouse', 
     '/(x|ch|ss|sh)es$/i' => '\1', 
     '/(m)ovies$/i' => '\1\2ovie', 
     '/(s)eries$/i' => '\1\2eries', 
     '/([^aeiouy]|qu)ies$/i' => '\1y', 
     '/([lr])ves$/i' => '\1f', 
     '/(tive)s$/i' => '\1', 
     '/(hive)s$/i' => '\1', 
     '/(drive)s$/i' => '\1', 
     '/([^fo])ves$/i' => '\1fe', 
     '/(^analy)ses$/i' => '\1sis', 
     '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis', 
     '/([ti])a$/i' => '\1um', 
     '/(p)eople$/i' => '\1\2erson', 
     '/(m)en$/i' => '\1an', 
     '/(c)hildren$/i' => '\1\2hild', 
     '/(n)ews$/i' => '\1\2ews', 
     '/(n)etherlands$/i' => '\1\2etherlands', 
     '/eaus$/' => 'eau', 
     '/^(.*us)$/' => '\\1', 
     '/s$/i' => '', 
    ]; 
    /** 
    * @var array the special rules for converting a word between its plural form and singular form. 
    * The keys are the special words in singular form, and the values are the corresponding plural form. 
    */ 
    public static $specials = [ 
     'atlas' => 'atlases', 
     'beef' => 'beefs', 
     'brother' => 'brothers', 
     'cafe' => 'cafes', 
     'child' => 'children', 
     'cookie' => 'cookies', 
     'corpus' => 'corpuses', 
     'cow' => 'cows', 
     'curve' => 'curves', 
     'foe' => 'foes', 
     'ganglion' => 'ganglions', 
     'genie' => 'genies', 
     'genus' => 'genera', 
     'graffito' => 'graffiti', 
     'hoof' => 'hoofs', 
     'loaf' => 'loaves', 
     'man' => 'men', 
     'money' => 'monies', 
     'mongoose' => 'mongooses', 
     'move' => 'moves', 
     'mythos' => 'mythoi', 
     'niche' => 'niches', 
     'numen' => 'numina', 
     'occiput' => 'occiputs', 
     'octopus' => 'octopuses', 
     'opus' => 'opuses', 
     'ox' => 'oxen', 
     'penis' => 'penises', 
     'sex' => 'sexes', 
     'soliloquy' => 'soliloquies', 
     'testis' => 'testes', 
     'trilby' => 'trilbys', 
     'turf' => 'turfs', 
     'wave' => 'waves', 
     'Amoyese' => 'Amoyese', 
     'bison' => 'bison', 
     'Borghese' => 'Borghese', 
     'bream' => 'bream', 
     'breeches' => 'breeches', 
     'britches' => 'britches', 
     'buffalo' => 'buffalo', 
     'cantus' => 'cantus', 
     'carp' => 'carp', 
     'chassis' => 'chassis', 
     'clippers' => 'clippers', 
     'cod' => 'cod', 
     'coitus' => 'coitus', 
     'Congoese' => 'Congoese', 
     'contretemps' => 'contretemps', 
     'corps' => 'corps', 
     'debris' => 'debris', 
     'diabetes' => 'diabetes', 
     'djinn' => 'djinn', 
     'eland' => 'eland', 
     'elk' => 'elk', 
     'equipment' => 'equipment', 
     'Faroese' => 'Faroese', 
     'flounder' => 'flounder', 
     'Foochowese' => 'Foochowese', 
     'gallows' => 'gallows', 
     'Genevese' => 'Genevese', 
     'Genoese' => 'Genoese', 
     'Gilbertese' => 'Gilbertese', 
     'graffiti' => 'graffiti', 
     'headquarters' => 'headquarters', 
     'herpes' => 'herpes', 
     'hijinks' => 'hijinks', 
     'Hottentotese' => 'Hottentotese', 
     'information' => 'information', 
     'innings' => 'innings', 
     'jackanapes' => 'jackanapes', 
     'Kiplingese' => 'Kiplingese', 
     'Kongoese' => 'Kongoese', 
     'Lucchese' => 'Lucchese', 
     'mackerel' => 'mackerel', 
     'Maltese' => 'Maltese', 
     'mews' => 'mews', 
     'moose' => 'moose', 
     'mumps' => 'mumps', 
     'Nankingese' => 'Nankingese', 
     'news' => 'news', 
     'nexus' => 'nexus', 
     'Niasese' => 'Niasese', 
     'Pekingese' => 'Pekingese', 
     'Piedmontese' => 'Piedmontese', 
     'pincers' => 'pincers', 
     'Pistoiese' => 'Pistoiese', 
     'pliers' => 'pliers', 
     'Portuguese' => 'Portuguese', 
     'proceedings' => 'proceedings', 
     'rabies' => 'rabies', 
     'rice' => 'rice', 
     'rhinoceros' => 'rhinoceros', 
     'salmon' => 'salmon', 
     'Sarawakese' => 'Sarawakese', 
     'scissors' => 'scissors', 
     'series' => 'series', 
     'Shavese' => 'Shavese', 
     'shears' => 'shears', 
     'siemens' => 'siemens', 
     'species' => 'species', 
     'swine' => 'swine', 
     'testes' => 'testes', 
     'trousers' => 'trousers', 
     'trout' => 'trout', 
     'tuna' => 'tuna', 
     'Vermontese' => 'Vermontese', 
     'Wenchowese' => 'Wenchowese', 
     'whiting' => 'whiting', 
     'wildebeest' => 'wildebeest', 
     'Yengeese' => 'Yengeese', 
    ]; 
    /** 
    * @var array fallback map for transliteration used by [[transliterate()]] when intl isn't available. 
    */ 
    public static $transliteration = [ 
     'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'AE', 'Ç' => 'C', 
     'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 
     'Ð' => 'D', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O', 'Ő' => 'O', 
     'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ű' => 'U', 'Ý' => 'Y', 'Þ' => 'TH', 
     'ß' => 'ss', 
     'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'ae', 'ç' => 'c', 
     'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 
     'ð' => 'd', 'ñ' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ő' => 'o', 
     'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ü' => 'u', 'ű' => 'u', 'ý' => 'y', 'þ' => 'th', 
     'ÿ' => 'y', 
    ]; 
    /** 
    * Shortcut for `Any-Latin; NFKD` transliteration rule. The rule is strict, letters will be transliterated with 
    * the closest sound-representation chars. The result may contain any UTF-8 chars. For example: 
    * `获取到 どちら Українська: ґ,є, Српска: ђ, њ, џ! ¿Español?` will be transliterated to 
    * `huò qǔ dào dochira Ukraí̈nsʹka: g̀,ê, Srpska: đ, n̂, d̂! ¿Español?` 
    * 
    * Used in [[transliterate()]]. 
    * For detailed information see [unicode normalization forms](http://unicode.org/reports/tr15/#Normalization_Forms_Table) 
    * @see http://unicode.org/reports/tr15/#Normalization_Forms_Table 
    * @see transliterate() 
    * @since 2.0.7 
    */ 
    const TRANSLITERATE_STRICT = 'Any-Latin; NFKD'; 
    /** 
    * Shortcut for `Any-Latin; Latin-ASCII` transliteration rule. The rule is medium, letters will be 
    * transliterated to characters of Latin-1 (ISO 8859-1) ASCII table. For example: 
    * `获取到 どちら Українська: ґ,є, Српска: ђ, њ, џ! ¿Español?` will be transliterated to 
    * `huo qu dao dochira Ukrainsʹka: g,e, Srpska: d, n, d! ¿Espanol?` 
    * 
    * Used in [[transliterate()]]. 
    * For detailed information see [unicode normalization forms](http://unicode.org/reports/tr15/#Normalization_Forms_Table) 
    * @see http://unicode.org/reports/tr15/#Normalization_Forms_Table 
    * @see transliterate() 
    * @since 2.0.7 
    */ 
    const TRANSLITERATE_MEDIUM = 'Any-Latin; Latin-ASCII'; 
    /** 
    * Shortcut for `Any-Latin; Latin-ASCII; [\u0080-\uffff] remove` transliteration rule. The rule is loose, 
    * letters will be transliterated with the characters of Basic Latin Unicode Block. 
    * For example: 
    * `获取到 どちら Українська: ґ,є, Српска: ђ, њ, џ! ¿Español?` will be transliterated to 
    * `huo qu dao dochira Ukrainska: g,e, Srpska: d, n, d! Espanol?` 
    * 
    * Used in [[transliterate()]]. 
    * For detailed information see [unicode normalization forms](http://unicode.org/reports/tr15/#Normalization_Forms_Table) 
    * @see http://unicode.org/reports/tr15/#Normalization_Forms_Table 
    * @see transliterate() 
    * @since 2.0.7 
    */ 
    const TRANSLITERATE_LOOSE = 'Any-Latin; Latin-ASCII; [\u0080-\uffff] remove'; 

    /** 
    * @var mixed Either a [[\Transliterator]], or a string from which a [[\Transliterator]] can be built 
    * for transliteration. Used by [[transliterate()]] when intl is available. Defaults to [[TRANSLITERATE_LOOSE]] 
    * @see http://php.net/manual/en/transliterator.transliterate.php 
    */ 
    public static $transliterator = self::TRANSLITERATE_LOOSE; 


    /** 
    * Converts a word to its plural form. 
    * Note that this is for English only! 
    * For example, 'apple' will become 'apples', and 'child' will become 'children'. 
    * @param string $word the word to be pluralized 
    * @return string the pluralized word 
    */ 
    public static function pluralize($word) 
    { 
     if (isset(static::$specials[$word])) { 
      return static::$specials[$word]; 
     } 
     foreach (static::$plurals as $rule => $replacement) { 
      if (preg_match($rule, $word)) { 
       return preg_replace($rule, $replacement, $word); 
      } 
     } 

     return $word; 
    } 

    /** 
    * Returns the singular of the $word 
    * @param string $word the english word to singularize 
    * @return string Singular noun. 
    */ 
    public static function singularize($word) 
    { 
     $result = array_search($word, static::$specials, true); 
     if ($result !== false) { 
      return $result; 
     } 
     foreach (static::$singulars as $rule => $replacement) { 
      if (preg_match($rule, $word)) { 
       return preg_replace($rule, $replacement, $word); 
      } 
     } 

     return $word; 
    } 

    /** 
    * Converts an underscored or CamelCase word into a English 
    * sentence. 
    * @param string $words 
    * @param boolean $ucAll whether to set all words to uppercase 
    * @return string 
    */ 
    public static function titleize($words, $ucAll = false) 
    { 
     $words = static::humanize(static::underscore($words), $ucAll); 

     return $ucAll ? ucwords($words) : ucfirst($words); 
    } 

    /** 
    * Returns given word as CamelCased 
    * Converts a word like "send_email" to "SendEmail". It 
    * will remove non alphanumeric character from the word, so 
    * "who's online" will be converted to "WhoSOnline" 
    * @see variablize() 
    * @param string $word the word to CamelCase 
    * @return string 
    */ 
    public static function camelize($word) 
    { 
     return str_replace(' ', '', ucwords(preg_replace('/[^A-Za-z0-9]+/', ' ', $word))); 
    } 

    /** 
    * Converts a CamelCase name into space-separated words. 
    * For example, 'PostTag' will be converted to 'Post Tag'. 
    * @param string $name the string to be converted 
    * @param boolean $ucwords whether to capitalize the first letter in each word 
    * @return string the resulting words 
    */ 
    public static function camel2words($name, $ucwords = true) 
    { 
     $label = trim(strtolower(str_replace([ 
      '-', 
      '_', 
      '.' 
     ], ' ', preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $name)))); 

     return $ucwords ? ucwords($label) : $label; 
    } 

    /** 
    * Converts a CamelCase name into an ID in lowercase. 
    * Words in the ID may be concatenated using the specified character (defaults to '-'). 
    * For example, 'PostTag' will be converted to 'post-tag'. 
    * @param string $name the string to be converted 
    * @param string $separator the character used to concatenate the words in the ID 
    * @param boolean|string $strict whether to insert a separator between two consecutive uppercase chars, defaults to false 
    * @return string the resulting ID 
    */ 
    public static function camel2id($name, $separator = '-', $strict = false) 
    { 
     $regex = $strict ? '/[A-Z]/' : '/(?<![A-Z])[A-Z]/'; 
     if ($separator === '_') { 
      return trim(strtolower(preg_replace($regex, '_\0', $name)), '_'); 
     } else { 
      return trim(strtolower(str_replace('_', $separator, preg_replace($regex, $separator . '\0', $name))), $separator); 
     } 
    } 

    /** 
    * Converts an ID into a CamelCase name. 
    * Words in the ID separated by `$separator` (defaults to '-') will be concatenated into a CamelCase name. 
    * For example, 'post-tag' is converted to 'PostTag'. 
    * @param string $id the ID to be converted 
    * @param string $separator the character used to separate the words in the ID 
    * @return string the resulting CamelCase name 
    */ 
    public static function id2camel($id, $separator = '-') 
    { 
     return str_replace(' ', '', ucwords(implode(' ', explode($separator, $id)))); 
    } 

    /** 
    * Converts any "CamelCased" into an "underscored_word". 
    * @param string $words the word(s) to underscore 
    * @return string 
    */ 
    public static function underscore($words) 
    { 
     return strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $words)); 
    } 

    /** 
    * Returns a human-readable string from $word 
    * @param string $word the string to humanize 
    * @param boolean $ucAll whether to set all words to uppercase or not 
    * @return string 
    */ 
    public static function humanize($word, $ucAll = false) 
    { 
     $word = str_replace('_', ' ', preg_replace('/_id$/', '', $word)); 

     return $ucAll ? ucwords($word) : ucfirst($word); 
    } 

    /** 
    * Same as camelize but first char is in lowercase. 
    * Converts a word like "send_email" to "sendEmail". It 
    * will remove non alphanumeric character from the word, so 
    * "who's online" will be converted to "whoSOnline" 
    * @param string $word to lowerCamelCase 
    * @return string 
    */ 
    public static function variablize($word) 
    { 
     $word = static::camelize($word); 

     return strtolower($word[0]) . substr($word, 1); 
    } 

    /** 
    * Converts a class name to its table name (pluralized) 
    * naming conventions. For example, converts "Person" to "people" 
    * @param string $className the class name for getting related table_name 
    * @return string 
    */ 
    public static function tableize($className) 
    { 
     return static::pluralize(static::underscore($className)); 
    } 

    /** 
    * Returns a string with all spaces converted to given replacement, 
    * non word characters removed and the rest of characters transliterated. 
    * 
    * If intl extension isn't available uses fallback that converts latin characters only 
    * and removes the rest. You may customize characters map via $transliteration property 
    * of the helper. 
    * 
    * @param string $string An arbitrary string to convert 
    * @param string $replacement The replacement to use for spaces 
    * @param boolean $lowercase whether to return the string in lowercase or not. Defaults to `true`. 
    * @return string The converted string. 
    */ 
    public static function slug($string, $replacement = '-', $lowercase = true) 
    { 
     $string = static::transliterate($string); 
     $string = preg_replace('/[^a-zA-Z0-9=\s—–-]+/u', '', $string); 
     $string = preg_replace('/[=\s—–-]+/u', $replacement, $string); 
     $string = trim($string, $replacement); 

     return $lowercase ? strtolower($string) : $string; 
    } 

    /** 
    * Returns transliterated version of a string. 
    * 
    * If intl extension isn't available uses fallback that converts latin characters only 
    * and removes the rest. You may customize characters map via $transliteration property 
    * of the helper. 
    * 
    * @param string $string input string 
    * @param string|\Transliterator $transliterator either a [[Transliterator]] or a string 
    * from which a [[Transliterator]] can be built. 
    * @return string 
    * @since 2.0.7 this method is public. 
    */ 
    public static function transliterate($string, $transliterator = null) 
    { 
     if (static::hasIntl()) { 
      if ($transliterator === null) { 
       $transliterator = static::$transliterator; 
      } 

      return transliterator_transliterate($transliterator, $string); 
     } else { 
      return strtr($string, static::$transliteration); 
     } 
    } 

    /** 
    * @return boolean if intl extension is loaded 
    */ 
    protected static function hasIntl() 
    { 
     return extension_loaded('intl'); 
    } 

    /** 
    * Converts a table name to its class name. For example, converts "people" to "Person" 
    * @param string $tableName 
    * @return string 
    */ 
    public static function classify($tableName) 
    { 
     return static::camelize(static::singularize($tableName)); 
    } 

    /** 
    * Converts number to its ordinal English form. For example, converts 13 to 13th, 2 to 2nd ... 
    * @param integer $number the number to get its ordinal value 
    * @return string 
    */ 
    public static function ordinalize($number) 
    { 
     if (in_array($number % 100, range(11, 13))) { 
      return $number . 'th'; 
     } 
     switch ($number % 10) { 
      case 1: 
       return $number . 'st'; 
      case 2: 
       return $number . 'nd'; 
      case 3: 
       return $number . 'rd'; 
      default: 
       return $number . 'th'; 
     } 
    } 

    /** 
    * Converts a list of words into a sentence. 
    * 
    * Special treatment is done for the last few words. For example, 
    * 
    * ```php 
    * $words = ['Spain', 'France']; 
    * echo Inflector::sentence($words); 
    * // output: Spain and France 
    * 
    * $words = ['Spain', 'France', 'Italy']; 
    * echo Inflector::sentence($words); 
    * // output: Spain, France and Italy 
    * 
    * $words = ['Spain', 'France', 'Italy']; 
    * echo Inflector::sentence($words, ' & '); 
    * // output: Spain, France & Italy 
    * ``` 
    * 
    * @param array $words the words to be converted into an string 
    * @param string $twoWordsConnector the string connecting words when there are only two 
    * @param string $lastWordConnector the string connecting the last two words. If this is null, it will 
    * take the value of `$twoWordsConnector`. 
    * @param string $connector the string connecting words other than those connected by 
    * $lastWordConnector and $twoWordsConnector 
    * @return string the generated sentence 
    * @since 2.0.1 
    */ 
    public static function sentence(array $words, $twoWordsConnector = ' and ', $lastWordConnector = null, $connector = ', ') 
    { 
     if ($lastWordConnector === null) { 
      $lastWordConnector = $twoWordsConnector; 
     } 
     switch (count($words)) { 
      case 0: 
       return ''; 
      case 1: 
       return reset($words); 
      case 2: 
       return implode($twoWordsConnector, $words); 
      default: 
       return implode($connector, array_slice($words, 0, -1)) . $lastWordConnector . end($words); 
     } 
    } 
} 

Существует несколько примеров.

echo "Inflector Test"; 
require('PhInflector.php'); 
echo "<hr>"; 
echo PhInflector::slug('Höäpeäöäich Médsui27:;;,.1! *"29p'); 
echo "<hr>"; 
echo PhInflector::slug('HIJO"$(/&T §!"(/&T"§:;;,.1! *"29p'); 
echo "<hr>"; 
echo PhInflector::slug('38917 jiodj d       ! *"29p'); 
echo "<hr>"; 
echo PhInflector::slug('каи циефле ///!!!'); 

И переслать github ссылку на номер here.

0

Рассмотрим пакет питона «гнуть»

«Правильно генерировать множественном, сингулярные существительные, числительные, неопределенные артикли, преобразования чисел в слова»

https://pypi.python.org/pypi/inflect

0

я просто столкнуться с этой проблемой и разработали раствор через 10 мин.

Я думаю, что @paxdiablo дает хорошую мысль о создании трансформирующего двигателя и добавлении правил. Я строю одно правило словаря и три общих правила. Правило словаря переходит в файл dict для поиска исключений, тогда как три общих правила обрабатывают «ies», «es» и «s» соответственно.

Однако для добавления всех исключений из словаря, например, pies/trees/bus и т. Д., Может потребоваться слишком много времени. Одно улучшение, которое я сделал для решения этих слов, - это убедиться, что оно может быть преобразовано обратно.

Например, если мы неправильно применяем правило «es» к «деревьям» и преобразуем его в «tre», при попытке добавить множественную форму назад вы получите «tres», который не равен оригинальное «дерево», и вы знаете, что правило «es» не должно применяться. Этот метод может решить вышеупомянутые исключения, не добавляя их в файл словаря.

В итоге я получил файл словаря из 42 действительно исключительных слов, и он мог обрабатывать большинство случаев.

 Смежные вопросы

  • Нет связанных вопросов^_^