Фэндом

Банк скриптов для голосового движка Festival Wiki

Порядковые числительные

13статей на
этой вики
Добавить новую страницу
Обсуждение0 Поделиться

Сценарий на баше, который умеет печатать в заданном падеже и роде порядковые числительные — в этой реализации от 0 до 999. В конце вывода нет символа перевода строки или пробела — мало ли где пригодится этот сценарий.

#!/bin/sh

NUMBER=1
GENUS=m #masculine
CASE=i #именительный падеж
MAX_SUPPORTED_NUMBER=999

print_help()
{
	echo Вывод порядкового числительного на русском языке в мужском роде единственного числа для заданного числа
	echo Поддерживаются числа от 0 до $MAX_SUPPORTED_NUMBER
	echo -e "Пример: \e[1mordinal -fcp 24\e[0m выведет «$($0 -fcp 24)»"
	echo -e "Число должно быть обязательно после параметров\n"
	echo Параметры сценария:
	echo -e "\t\e[1m-f\e[0m — в женском роде (feminine)"
	echo -e "\t\e[1m-m\e[0m — в мужском роде (masculine)"
	echo -e "\t\e[1m-n\e[0m — в среднем роде (neuter)\n"
	echo -e "\t\e[1m-p\e[0m — во множественном числе (plural)"
	echo -e "\t\e[1m-s\e[0m — в единственном числе (singular)\n"
	echo -e "\t\e[1m-u\e[0m — с большой буквы (upper)\n"
	echo -e "\t\e[1m-c\e[0m — падеж (case). Этот флаг требует параметра\n\t\tДопустимые значения параметра:\e[1mi\e[0m|\e[1mr\e[0m|\e[1md\e[0m|\e[1mt\e[0m|\e[1mp\e[0m\n\t\tПо умолчанию используется именительный.\n\t\tВинительный падеж изъят как неоднозначный, используйте именительный или родительный"
	echo -e "\t\e[1m-h\e[0m — Справка"
	echo -e "\t\e[1m-v\e[0m — Информация об авторе"
}

print_version() { echo Автор gluk47@gmail.com. Лицензия GPL v3. Версия 0.7; }

process_opts ()
{
	while getopts "hvpsmfnuc:" cur_opt $1; do
		case "$cur_opt" in
			h) print_help; EXIT_BY_CMD=yes;;
			v) print_version; EXIT_BY_CMD=yes;;
			m) GENUS=m;;
			f) GENUS=f;;
			n) GENUS=n;;
			s) [ -z "$GENUS" ] && GENUS=m;; #default
			p) GENUS=p;; #plural
			u) CAPITALIZE=yes;;
			c) CASE=$OPTARG;;
		esac
	done
}

# Сгенерировать корень количественного числительного
# Параметр [inout] __цифра__ (число из [0;9])
gen_cardinal_base ()
{
	local p=$(eval 'echo -n "$'$1'"')
	case $p in
		0) eval $1=нол;;
		1) eval $1=один;;
		2)	if [ "$2" == -f ]; then eval $1=две
			else eval $1=два
			fi;;
		3) eval $1=три;;
		4) eval $1=четыр;;
		5) eval $1=пять;;
		6) eval $1=шесть;;
		7) eval $1=семь;;
		8) eval $1=восемь;;
		8ь) eval $1=восьмь;;
		9) eval $1=девять;;
		*) eval $1=???;
	esac
}

# Cгенерировать корень слова. Параметр [inout] — число, для которого надо сгенерировать
# Глобальная переменная NUMBER может измениться при вызове gen_tens. Для правильного окончания *40 → *42
gen_base()
{
	local p=$(eval 'echo -n "$'$1'"')
	if [[ $p -le 19 ]]; then
		case $p in
			0) eval $1=нулев;;
			1) eval $1=перв;;
			2) eval $1=втор;;
			3) eval $1=трет;;
			4) eval $1=четвёрт;;
			5) eval $1=пят;;
			6) eval $1=шест;;
			7) eval $1=седьм;;
			8) eval $1=восьм;;
			9) eval $1=девят;;
			10) eval $1=десят;;
			11) eval $1=одиннадцат;;
			12) eval $1=двенадцат;;
			13) eval $1=тринадцат;;
			14) eval $1=четырнадцат;;
			15) eval $1=пятнадцат;;
			16) eval $1=шестнадцат;;
			17) eval $1=семнадцат;;
			18) eval $1=восемнадцат;;
			19) eval $1=девятнадцат;;
		esac
	else if [[ $p -le 99 ]]; then gen_tens $1
	else gen_hundreds $1
	fi fi
}

# Обработать двузначное число
# Параметр [inout] число целиком
# Глобальная переменная NUMBER может измениться. Для правильного окончания *40 → *42
gen_tens ()
{
	local p=$(eval 'echo -n "$'$1'"')
	local d
	let "d=$p/10%10"
	local dr
	let "dr=$p%10"
	[[ $d -eq 8 && $dr -eq 0 ]] && d=8ь
	case $d in
		2|3) gen_cardinal_base d; d=${d}дцат; [ "$dr" -ne 0 ] && d=${d}ь;;
		4) 	d=сорок
			if [ "$dr" -eq 0 ]; then
				d=${d}ов
				NUMBER=$(($NUMBER+2)) #для корректного определения окончания
			fi;;
		5|6|7|8ь|8) gen_cardinal_base d;
			[ "$dr" -eq 0 ] && d=${d%ь}и;
			d=${d}десят;;
		9) d=девяност;
			[ "$dr" -ne 0 ] && d=${d}о;;
	esac

	if [ "$dr" -ne 0 ]; then
		gen_base dr
		eval "$1=\"$d $dr\""
	else
		eval "$1=\"$d\""
	fi
}

gen_hundreds()
{
	local p=$(eval 'echo -n "$'$1'"')
	local h
	let "h=p/100%10"
	local r
	let "hr=$p%100"
	local ans

	if [[ $hr -ne 0 ]]; then
		case $h in
			1) ans=сто;;
			2) ans=двести;;
			3) ans=триста;;
			4) ans=четыреста;;
			*) ans=$h;
				gen_cardinal_base ans;
				ans=${ans}сот;;
		esac
		gen_base hr
		eval "$1=\"$ans $hr\""
	else
		[[ $h -eq 8 ]] && h=8ь
		case $h in
			1) ans="";;
			2) ans=двух;;
			3) ans=трёх;;
			4) ans=четырёх;;
			*) ans=$h
				gen_cardinal_base ans;
				ans=${ans%ь}и;;
		esac
		ans=${ans}сот
		eval "$1=\"$ans\""
	fi
}

gen_ending()
{
	local r
	let "r=$1 % 10"
	local d
	let "d=$1/10%10"

	case $GENUS in
		f)
			if [ $r -eq 3 -a $1 -ne 13 ]; then
				if [ $CASE == i ]; then ENDING=ья
				else ENDING=ьей
				fi
			else if [ $CASE == i ]; then ENDING=ая
				else ENDING=ой
				fi
			fi
			return;;
		p)	case $CASE in
				i) ENDING=ые;;
				r|p) ENDING=ых;;
				d) ENDING=ым;;
				t) ENDING=ыми;;
			esac
			return;;
	# именительный падеж мужского и среднего рода строятся по-разному
		n)
			if [ $CASE == i ]; then
				if [ $r -eq 3 -a $1 -ne 13 ]; then ENDING=ье
				else ENDING=ое
				fi
				return;
			fi;;
		m)
			if [ $CASE == i ]; then
				if [[ $d -eq 1 ]]; then ENDING=ый
				else if [[ $r -eq 3 ]]; then ENDING=ий
				else if [[ $r == 2 || $r -ge 6 && $r -le 8 ]]; then ENDING=ой
				else ENDING=ый #именно так минимизируется число сравнений
				fi fi fi
				return
			fi;;
		*) ENDING=??;;
	esac
	# косвенный падеж мужского или среднего рода
	if [ $r -eq 3 -a $1 -ne 13 ]; then
		case $CASE in
			r)	ENDING=ьего;;
			d)	ENDING=ьему;;
			t)	ENDING=ьим;;
			p)	ENDING=ьем;;
		esac
	else
		case $CASE in
			r)	ENDING=ого;;
			d)	ENDING=ому;;
			t)	ENDING=ым;;
			p)	ENDING=ом;;
		esac
	fi
}

### main ###
if [ "$1" == unittest ]; then
	shift 1
	for ((i=0; i<=9; i++)); do "$0" $* ${i}42; echo ""; done
	exit 0
fi
process_opts "$*"
[ -n "$EXIT_BY_CMD" ] && exit 0
shift $(($OPTIND - 1))
if [[ "$1" == --help ]]; then
	print_help; exit 0;
fi

[ -n "$2" ] && echo "Вероятно, вы указали параметр после числа. В данной версии это не поддерживается" >&2
if [ -z "$1" ]; then
	echo -e "Укажите число аргументом сценария или \e[1m-h\e[0m для справки"
	exit 3;
fi
NUMBER=$1
USER_REQUESTED_NUMBER=$1
BASE=$NUMBER
gen_base BASE #NUMBER может измениться. Для правильного окончания *40 → *42
[[ $NUMBER -eq 0 ]] && ((NUMBER += 2))
gen_ending $NUMBER
WORD="$BASE$ENDING"
echo -n $WORD
[[ $USER_REQUESTED_NUMBER -gt $MAX_SUPPORTED_NUMBER ]] && exit 1
exit 0

Примеры:

$ ordinal -f -cp 242
двести сорок второй
$ ordinal -n 42
сорок второе
$ ordinal 1000
нолисотый
$ ordinal -h
Вывод порядкового числительного на русском языке в мужском роде единственного числа для заданного числа
Поддерживаются числа от 0 до 999
Пример: ordinal -fcp 24 выведет «двадцать четвёртой»
Число должно быть обязательно после параметров

Параметры сценария:
        -f — в женском роде (feminine)
        -m — в мужском роде (masculine)
        -n — в среднем роде (neuter)

        -p — во множественном числе (plural)
        -s — в единственном числе (singular)

        -u — с большой буквы (upper)

        -c — падеж (case). Этот флаг требует параметра
                Допустимые значения параметра:i|r|d|t|p
                По умолчанию используется именительный.
                Винительный падеж изъят как неоднозначный, используйте именительный или родительный
        -h — Справка
        -v — Информация об авторе

Обнаружено использование расширения AdBlock.


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

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

Также на Фэндоме

Случайная вики