JavaScript复数英文字符串

Posted

技术标签:

【中文标题】JavaScript复数英文字符串【英文标题】:JavaScript pluralize an english string 【发布时间】:2015-01-27 10:47:19 【问题描述】:

php 中,我使用 Kuwamoto 的类将字符串中的名词复数。除了一些插件外,我在 javascript 中没有找到像这个脚本一样好的东西。所以,如果有一个基于 Kuwamoto 的类的 javascript 函数就好了。

http://kuwamoto.org/2007/12/17/improved-pluralizing-in-php-actionscript-and-ror/

【问题讨论】:

【参考方案1】:

简单版(ES6):

const maybePluralize = (count, noun, suffix = 's') =>
  `$count $noun$count !== 1 ? suffix : ''`;

用法:

maybePluralize(0, 'turtle'); // 0 turtles
maybePluralize(1, 'turtle'); // 1 turtle
maybePluralize(2, 'turtle'); // 2 turtles
maybePluralize(3, 'fox', 'es'); // 3 foxes

这显然不支持所有英语边缘情况,但它适用于大多数用途

【讨论】:

有人可以为maybePluralize建议其他名称吗? localize, plural @thisshri 我用过pluralize 翻译怎么样?【参考方案2】:

使用Pluralize

有一个很棒的小库 Pluralize 打包在 npm 和 bower 中。

这就是它的用法:

import Pluralize from 'pluralize';

Pluralize( 'Towel', 42 );       // "Towels"

Pluralize( 'Towel', 42, true ); // "42 Towels"

你可以在这里得到它:

https://github.com/blakeembrey/pluralize

【讨论】:

感谢@JoshuaPinter,我当时正在处理 ies,使用自定义函数然后认为那里必须有一些东西,正是我正在寻找的东西。 @ak85 添加另一个依赖项并不总是解决方案,但是当它是这样的时候,很容易理解并且不是关键的,它很有意义。站在巨人的肩膀上。【参考方案3】:

所以,我通过在 Kuwamoto 的 PHP 类的 javascript 中分享我的翻译来回答我自己的问题。

String.prototype.plural = function(revert)

    var plural = 
        '(quiz)$'               : "$1zes",
        '^(ox)$'                : "$1en",
        '([m|l])ouse$'          : "$1ice",
        '(matr|vert|ind)ix|ex$' : "$1ices",
        '(x|ch|ss|sh)$'         : "$1es",
        '([^aeiouy]|qu)y$'      : "$1ies",
        '(hive)$'               : "$1s",
        '(?:([^f])fe|([lr])f)$' : "$1$2ves",
        '(shea|lea|loa|thie)f$' : "$1ves",
        'sis$'                  : "ses",
        '([ti])um$'             : "$1a",
        '(tomat|potat|ech|her|vet)o$': "$1oes",
        '(bu)s$'                : "$1ses",
        '(alias)$'              : "$1es",
        '(octop)us$'            : "$1i",
        '(ax|test)is$'          : "$1es",
        '(us)$'                 : "$1es",
        '([^s]+)$'              : "$1s"
    ;

    var singular = 
        '(quiz)zes$'             : "$1",
        '(matr)ices$'            : "$1ix",
        '(vert|ind)ices$'        : "$1ex",
        '^(ox)en$'               : "$1",
        '(alias)es$'             : "$1",
        '(octop|vir)i$'          : "$1us",
        '(cris|ax|test)es$'      : "$1is",
        '(shoe)s$'               : "$1",
        '(o)es$'                 : "$1",
        '(bus)es$'               : "$1",
        '([m|l])ice$'            : "$1ouse",
        '(x|ch|ss|sh)es$'        : "$1",
        '(m)ovies$'              : "$1ovie",
        '(s)eries$'              : "$1eries",
        '([^aeiouy]|qu)ies$'     : "$1y",
        '([lr])ves$'             : "$1f",
        '(tive)s$'               : "$1",
        '(hive)s$'               : "$1",
        '(li|wi|kni)ves$'        : "$1fe",
        '(shea|loa|lea|thie)ves$': "$1f",
        '(^analy)ses$'           : "$1sis",
        '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$': "$1$2sis",        
        '([ti])a$'               : "$1um",
        '(n)ews$'                : "$1ews",
        '(h|bl)ouses$'           : "$1ouse",
        '(corpse)s$'             : "$1",
        '(us)es$'                : "$1",
        's$'                     : ""
    ;

    var irregular = 
        'move'   : 'moves',
        'foot'   : 'feet',
        'goose'  : 'geese',
        'sex'    : 'sexes',
        'child'  : 'children',
        'man'    : 'men',
        'tooth'  : 'teeth',
        'person' : 'people'
    ;

    var uncountable = [
        'sheep', 
        'fish',
        'deer',
        'moose',
        'series',
        'species',
        'money',
        'rice',
        'information',
        'equipment'
    ];

    // save some time in the case that singular and plural are the same
    if(uncountable.indexOf(this.toLowerCase()) >= 0)
      return this;

    // check for irregular forms
    for(word in irregular)

      if(revert)
              var pattern = new RegExp(irregular[word]+'$', 'i');
              var replace = word;
       else var pattern = new RegExp(word+'$', 'i');
              var replace = irregular[word];
      
      if(pattern.test(this))
        return this.replace(pattern, replace);
    

    if(revert) var array = singular;
         else  var array = plural;

    // check for matches using regular expressions
    for(reg in array)

      var pattern = new RegExp(reg, 'i');

      if(pattern.test(this))
        return this.replace(pattern, array[reg]);
    

    return this;

易于使用:

alert("page".plural()); // return plural form => pages
alert("mouse".plural()); // return plural form => mice
alert("women".plural(true)); // return singular form => woman

DEMO

【讨论】:

扩展内置对象原型通常不是一个好主意。你可能想看看这个模块:github.com/blakeembrey/pluralize 复数数组有一个小错误。最后一项应该是'$' : 's' 而不是's$' : 's' @wout - 你是对的,我的错!我将其更改为 '(.)$' : '$1s' 以确保字符串中至少有一个字符 @pmrotule 仍然是个问题。使用'(.)$' : '$1s' 复数page 将导致pags。所以我转换回'$' : '$1s',并在上面添加了一个规则以防空字符串:'^$' : ''。现在它按我的预期工作了。 @wout - 这很奇怪。对于$1,它不应该替换任何现有字符。它对我很有效(page 将导致pages - 参见演示)。不过还是有问题,如果它已经是复数形式,会导致pagess,所以我将其修改为'([^s]+)$' : '$1s'【参考方案4】:

基于@pmrotule 回答,带有一些打字稿魔法和不可数数组的一些添加。我在这里添加了复数和单数功能。

复数形式:

/**
 * Returns the plural of an English word.
 *
 * @export
 * @param string word
 * @param number [amount]
 * @returns string
 */
export function plural(word: string, amount?: number): string 
    if (amount !== undefined && amount === 1) 
        return word
    
    const plural:  [key: string]: string  = 
        '(quiz)$'               : "$1zes",
        '^(ox)$'                : "$1en",
        '([m|l])ouse$'          : "$1ice",
        '(matr|vert|ind)ix|ex$' : "$1ices",
        '(x|ch|ss|sh)$'         : "$1es",
        '([^aeiouy]|qu)y$'      : "$1ies",
        '(hive)$'               : "$1s",
        '(?:([^f])fe|([lr])f)$' : "$1$2ves",
        '(shea|lea|loa|thie)f$' : "$1ves",
        'sis$'                  : "ses",
        '([ti])um$'             : "$1a",
        '(tomat|potat|ech|her|vet)o$': "$1oes",
        '(bu)s$'                : "$1ses",
        '(alias)$'              : "$1es",
        '(octop)us$'            : "$1i",
        '(ax|test)is$'          : "$1es",
        '(us)$'                 : "$1es",
        '([^s]+)$'              : "$1s"
    
    const irregular:  [key: string]: string  = 
        'move'   : 'moves',
        'foot'   : 'feet',
        'goose'  : 'geese',
        'sex'    : 'sexes',
        'child'  : 'children',
        'man'    : 'men',
        'tooth'  : 'teeth',
        'person' : 'people'
    
    const uncountable: string[] = [
        'sheep',
        'fish',
        'deer',
        'moose',
        'series',
        'species',
        'money',
        'rice',
        'information',
        'equipment',
        'bison',
        'cod',
        'offspring',
        'pike',
        'salmon',
        'shrimp',
        'swine',
        'trout',
        'aircraft',
        'hovercraft',
        'spacecraft',
        'sugar',
        'tuna',
        'you',
        'wood'
    ]
    // save some time in the case that singular and plural are the same
    if (uncountable.indexOf(word.toLowerCase()) >= 0) 
        return word
    
    // check for irregular forms
    for (const w in irregular) 
        const pattern = new RegExp(`$w$`, 'i')
        const replace = irregular[w]
        if (pattern.test(word)) 
            return word.replace(pattern, replace)
        
    
    // check for matches using regular expressions
    for (const reg in plural) 
        const pattern = new RegExp(reg, 'i')
        if (pattern.test(word)) 
            return word.replace(pattern, plural[reg])
        
    
    return word

还有单数版:

/**
 * Returns the singular of an English word.
 *
 * @export
 * @param string word
 * @param number [amount]
 * @returns string
 */
export function singular(word: string, amount?: number): string 
    if (amount !== undefined && amount !== 1) 
        return word
    
    const singular:  [key: string]: string  = 
        '(quiz)zes$'             : "$1",
        '(matr)ices$'            : "$1ix",
        '(vert|ind)ices$'        : "$1ex",
        '^(ox)en$'               : "$1",
        '(alias)es$'             : "$1",
        '(octop|vir)i$'          : "$1us",
        '(cris|ax|test)es$'      : "$1is",
        '(shoe)s$'               : "$1",
        '(o)es$'                 : "$1",
        '(bus)es$'               : "$1",
        '([m|l])ice$'            : "$1ouse",
        '(x|ch|ss|sh)es$'        : "$1",
        '(m)ovies$'              : "$1ovie",
        '(s)eries$'              : "$1eries",
        '([^aeiouy]|qu)ies$'     : "$1y",
        '([lr])ves$'             : "$1f",
        '(tive)s$'               : "$1",
        '(hive)s$'               : "$1",
        '(li|wi|kni)ves$'        : "$1fe",
        '(shea|loa|lea|thie)ves$': "$1f",
        '(^analy)ses$'           : "$1sis",
        '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$': "$1$2sis",
        '([ti])a$'               : "$1um",
        '(n)ews$'                : "$1ews",
        '(h|bl)ouses$'           : "$1ouse",
        '(corpse)s$'             : "$1",
        '(us)es$'                : "$1",
        's$'                     : ""
    
    const irregular:  [key: string]: string  = 
        'move'   : 'moves',
        'foot'   : 'feet',
        'goose'  : 'geese',
        'sex'    : 'sexes',
        'child'  : 'children',
        'man'    : 'men',
        'tooth'  : 'teeth',
        'person' : 'people'
    
    const uncountable: string[] = [
        'sheep',
        'fish',
        'deer',
        'moose',
        'series',
        'species',
        'money',
        'rice',
        'information',
        'equipment',
        'bison',
        'cod',
        'offspring',
        'pike',
        'salmon',
        'shrimp',
        'swine',
        'trout',
        'aircraft',
        'hovercraft',
        'spacecraft',
        'sugar',
        'tuna',
        'you',
        'wood'
    ]
    // save some time in the case that singular and plural are the same
    if (uncountable.indexOf(word.toLowerCase()) >= 0) 
        return word
    
    // check for irregular forms
    for (const w in irregular) 
        const pattern = new RegExp(`$irregular[w]$`, 'i')
        const replace = w
        if (pattern.test(word)) 
            return word.replace(pattern, replace)
        
    
    // check for matches using regular expressions
    for (const reg in singular) 
        const pattern = new RegExp(reg, 'i')
        if (pattern.test(word)) 
            return word.replace(pattern, singular[reg])
        
    
    return word

【讨论】:

感谢您清理它。如此多的答案将受益于像这样的纯封闭式函数。 ❤️ 只是完美的答案,以下是您在 Angular 中的操作方法:gist.github.com/ezzabuzaid/1d49eac3c2887702636c0975a3a06ace【参考方案5】:

ECMA 的新 intl API 规范将提供复数规则功能, https://github.com/tc39/proposal-intl-plural-rules

这是今天可以使用的polyfill https://github.com/eemeli/IntlPluralRules

【讨论】:

【参考方案6】:

摘自我的博客:https://sergiotapia.me/pluralizing-strings-in-javascript-es6-b5d4d651d403


您可以为此使用pluralize 库。

NPM:
npm install pluralize --save

Yarn:
yarn add pluralize

无论您想在哪里使用该库,都可以轻松地使用它。

var pluralize = require('pluralize')

我喜欢将它添加到窗口对象中,这样我就可以在需要的地方调用复数()。在我的 application.js 根文件中:

window.pluralize = require('pluralize')

然后你可以在任何地方使用它,React 组件,或者只是简单的 Javascript:

<span className="pull-left">
  `$item.score $pluralize('point', item.score)`
</span>

console.log(pluralize('point', item.score))

【讨论】:

我很困惑,我对“Use Pluralize”的回答不清楚您需要写这个答案吗?【参考方案7】:

我使用这个简单的内联语句

const number = 2;
const string = `$number trutle$number === 1 ? "" : "s"`; //this one
console.log(string)

【讨论】:

【参考方案8】:
function pluralize( /* n, [ n2, n3, ... ] str */ ) 
    var n = Array.prototype.slice.call( arguments ) ;
    var str = n.pop(), iMax = n.length - 1, i = -1, j ;
    str = str.replace( /\$\$|\$(\d+)/g,
        function( m, p1 )  return m == '$$' ? '$' : n[+p1-1] 
    ) ;
    return str.replace( /[(](.*?)([+-])(\d*)(?:,([^,)]*))?(?:,([^)]*))?[)]/g,
        function( match, one, sign, abs, not1, zero ) 
            // if abs, use indicated element in the array of numbers
            // instead of using the next element in sequence
            abs ? ( j = +abs - 1 ) : ( i < iMax && i++, j = i ) ;
            if ( zero != undefined && n[j] == 0 ) return zero ;
            return ( n[j] != 1 ) == ( sign == '+' ) ? ( not1 || 's' ) : one ;
        
    ) ;  


console.log( pluralize( 1, 'the cat(+) live(-) outside' ) ) ;
// the cat lives outside
console.log( pluralize( 2, 'the child(+,ren) (is+,are) inside' ) ) ;
// the children are inside
console.log( pluralize( 0, '$1 dog(+), ($1+,$1,no) dog(+), ($1+,$1,no) dog(+,,)' ) ) ;
// 0 dogs, no dogs, no dog
console.log( pluralize( 100, 1, '$1 penn(y+,ies) make(-1) $$$2' ) ) ;
// 100 pennies make $1
console.log( pluralize( 1, 0.01, '$1 penn(y+,ies) make(-1) $$$2' ) ) ;
// 1 penny makes $0.01

【讨论】:

不鼓励对解决方案的代码进行证明。请提供解释解决方案,它是如何解决问题的。【参考方案9】:

我创建了一个非常简单的库,可用于 JavaScript 中的单词复数。它透明地将 CLDR 数据库用于多个语言环境,因此它几乎支持您想要使用的任何语言。它的 API 非常简约,集成非常简单。它叫Numerous。

我还写了一篇介绍它的小文章:«How to pluralize any word in different languages using JavaScript?»。

随意在您的项目中使用它。我也会很高兴收到您对此的反馈。

【讨论】:

【参考方案10】:

使用@sarink 的回答,我制作了一个函数来使用键值对数据和复数键创建一个字符串。这是sn-p:

// Function to create a string from given key value pairs and pluralize keys
const stringPluralize = function(data)
    var suffix = 's';
    var str = '';
    $.each(data, function(key, val)
        if(str != '')
            str += val>0 ? ` and $val $key$val !== 1 ? suffix : ''` : '';
        
        else
            str = val>0 ? `$val $key$val !== 1 ? suffix : ''` : '';
        
    );
    return str;

var leftDays = '1';
var leftHours = '12';
var str = stringPluralize(day:leftDays, hour:leftHours);
console.log(str) // Gives 1 day and 12 hours

【讨论】:

【参考方案11】:

提供一个简单易读的选项(ES6):

export function pluralizeAndStringify(value, word, suffix = 's')
   if (value == 1)
    return value + ' ' + word;
   
   else 
    return value + ' ' + word + suffix;
   

如果您提供pluralizeAndStringify(5, 'dog') 之类的内容,您将得到“5 条狗”作为输出。

【讨论】:

category 这样的词呢?应该是categories【参考方案12】:

如果单词以ay结尾,使用-ies,如果单词以-s、-ss、-sh、-ch、-x或-z结尾,使用-es,如果world使用非法复数查找表是不规则复数,否则使用-s。

var pluralize = (function () 
  var vowels = "aeiou";
  var irregulars = "addendum":"addenda","aircraft":"aircraft","alumna":"alumnae","alumnus":"alumni","analysis":"analyses","antenna":"antennae","antithesis":"antitheses","apex":"apices","appendix":"appendices","axis":"axes","bacillus":"bacilli","bacterium":"bacteria","basis":"bases","beau":"beaux","bison":"bison","bureau":"bureaux","cactus":"cacti","château":"châteaux","child":"children","codex":"codices","concerto":"concerti","corpus":"corpora","crisis":"crises","criterion":"criteria","curriculum":"curricula","datum":"data","deer":"deer","diagnosis":"diagnoses","die":"dice","dwarf":"dwarves","ellipsis":"ellipses","erratum":"errata","faux pas":"faux pas","fez":"fezzes","fish":"fish","focus":"foci","foot":"feet","formula":"formulae","fungus":"fungi","genus":"genera","goose":"geese","graffito":"graffiti","grouse":"grouse","half":"halves","hoof":"hooves","hypothesis":"hypotheses","index":"indices","larva":"larvae","libretto":"libretti","loaf":"loaves","locus":"loci","louse":"lice","man":"men","matrix":"matrices","medium":"media","memorandum":"memoranda","minutia":"minutiae","moose":"moose","mouse":"mice","nebula":"nebulae","nucleus":"nuclei","oasis":"oases","offspring":"offspring","opus":"opera","ovum":"ova","ox":"oxen","parenthesis":"parentheses","phenomenon":"phenomena","phylum":"phyla","quiz":"quizzes","radius":"radii","referendum":"referenda","salmon":"salmon","scarf":"scarves","self":"selves","series":"series","sheep":"sheep","shrimp":"shrimp","species":"species","stimulus":"stimuli","stratum":"strata","swine":"swine","syllabus":"syllabi","symposium":"symposia","synopsis":"synopses","tableau":"tableaux","thesis":"theses","thief":"thieves","tooth":"teeth","trout":"trout","tuna":"tuna","vertebra":"vertebrae","vertex":"vertices","vita":"vitae","vortex":"vortices","wharf":"wharves","wife":"wives","wolf":"wolves","woman":"women", "guy": "guys" ,"buy": "buys", "person": "people";

  function pluralize(word) 
    if(irregulars[word]) 
      return irregulars[word];
     else if(word[word.length - 1] === "s" || word.endsWith("sh") || word.endsWith("ch") || word[word.length - 1] === "x" || word[word.length - 1] === "z") 
      return word + "es";
     else if(word[word.length - 1] === "y")  
      return word.substring(0, word.length - 1) + "ies";
     else 
      return word + "s";
    
  
   
   return pluralize;
)();

////////////////////////////////////////
console.log(pluralize("dog"));
console.log(pluralize("cat"));
console.log(pluralize("fox"));
console.log(pluralize("dwarf"));

显然,这不能支持所有英语边缘情况,但它有最常见的情况。

【讨论】:

以上是关于JavaScript复数英文字符串的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 中的字符串原语和字符串对象有啥区别?

JavaScript实现以个复数类

javascript 复数rus

javascript文件的命名规则求教

javascript [webgl的]复数メッシュ表示

JavaScript高级程序设计笔记之面向对象