В начале века я пользовался функцией на парсере, не уверен, что точно знаю, кем написанной, и не знаю, где сегодня найти в архиве. Она умела выбирать правильный падеж существительного, поставленного после числа. Хорошо помню, что она называлась ^rightCase[], но сходу не смог найти ее в бекапах. Но зато нашел ее предшественницу:
@grammar[count]
$count[0$count]
$last2[^count.match[(\d\d)^$]]
$last2[$last2.1]
^if(^last2.match[[02-9]1]){
$ending[]
}{
^if(^last2.match[[2-4]^$]){
$ending[а]
}{
$ending[ов]
}
}
$result[язык$ending]
Потом долгое время пользовался (и продолжаю) функцией на перле, переписанной по мотивам этого алгоритма, и размещенной на спане в модуле Lingua::RU::Numeric::Declension:
sub numdecl {
my ($number, $nominative, $genitive, $plural) = @_;
return $plural if $number =~ /1.$/;
my ($last_digit) = $number =~ /(.)$/;
return $nominative if $last_digit == 1;
return $genitive if $last_digit > 0 && $last_digit < 5;
return $plural;
}
А сегодня еще раз скопировал этот алгоритм, но уже на XSLT:
<func:function name="w:declension">
<xsl:param name="number"/>
<xsl:param name="nominative"/>
<xsl:param name="genitive"/>
<xsl:param name="plural"/>
<xsl:variable name="length" select="string-length(string($number))"/>
<xsl:variable name="last" select="substring(string($number), $length, 1)"/>
<func:result>
<xsl:choose>
<xsl:when test="$length > 1 and substing(string($number), $length - 1, 1) = '1'">
<xsl:value-of select="$plural"/>
</xsl:when>
<xsl:when test="$last = '1'">
<xsl:value-of select="$nominative"/>
</xsl:when>
<xsl:when test="$last > 0 and $last < 5">
<xsl:value-of select="$genitive"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$plural"/>
</xsl:otherwise>
</xsl:choose>
</func:result>
</func:function>
Какая из этого мораль? Да такая, что в большинстве случаев выбор языка не важен.
Не обязательно усложнять жизнь регэкспами:
# Russian, Ukrainian, Belarusian, Croatian, Serbian if ($lang eq 'ru' || $lang eq 'uk' || $lang eq 'be' || $lang eq 'hr' || $lang eq 'sr') { $r = sub { my $n = shift; $n = -$n if $n < 0; # nplurals = 3 return $n % 10 == 1 && $n % 100 != 11 ? 0 : $n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2; } }Верстка пожрала код в коменте.
Вот здесь полностью + много всяких языков:
Текущая версия для Парсера:
Было бы полезно параметры к функциям задокументировать.
А то мне, например, не понятно, что куда класть в XSLT.