Вопрос или проблема
Мне нужно написать скрипт на Linux, который конвертирует числа в полные написанные слова. Из-за нехватки времени мне придется обойтись кодом без исключений и чисел после запятой, но он все равно не работает. Программа не распознает переменные, поэтому мне в основном нужна помощь с синтаксисом. Вот что у меня есть на данный момент (на нидерландском).
Обновление: Я перевел наиболее важную (как я считаю) часть на английский.
#!/bin/bash
echo -prijs "Введите цену: "
read price
thousands="expr $price /1000"
hundreds="expr ($price - $thousands) / 100"
teens="expr ($price - $hundreds - $thousands / 10"
units="expr $price - $hundreds - $thousands - $teens"
for ((i=0 ; i<=$thousands; i++ ))
do
case $thousands in
0) echo -prijs "";;
1) echo -prijs "тысяча";;
2) echo -prijs "две тысячи";;
3) echo -prijs "три тысячи";;
4) echo -prijs "четыре тысячи";;
5) echo -prijs "пять тысяч";;
6) echo -prijs "шесть тысяч";;
7) echo -prijs "семь тысяч";;
8) echo -prijs "восемь тысяч";;
9) echo -prijs "девять тысяч";;
10) echo -prijs "десять тысяч";;
esac
done
for ((i=0 ; i<=$hundreds; i++ ))
do
case $hundreds in
0) echo -prijs "";;
1) echo -prijs "сто";;
2) echo -prijs "двести";;
3) echo -prijs "триста";;
4) echo -prijs "четыреста";;
5) echo -prijs "пятьсот";;
6) echo -prijs "шестьсот";;
7) echo -prijs "семьсот";;
8) echo -prijs "восемьсот";;
9) echo -prijs "девятьсот";;
esac
done
for ((i=0 ; i<=$teens; i++ ))
do
case $teens in
0) echo -prijs "";;
1) echo -prijs "десять";;
2) echo -prijs "двадцать";;
3) echo -prijs "тридцать";;
4) echo -prijs "сорок";;
5) echo -prijs "пятьдесят";;
6) echo -prijs "шестьдесят";;
7) echo -prijs "семьдесят";;
8) echo -prijs "восемьдесят";;
9) echo -prijs "девяносто";;
esac
done
for ((i=0 ; i<=$units; i++ ))
do
case $units in
0) echo -prijs "";;
1) echo -prijs "один";;
2) echo -prijs "два";;
3) echo -prijs "три";;
4) echo -prijs "четыре";;
5) echo -prijs "пять";;
6) echo -prijs "шесть";;
7) echo -prijs "семь";;
8) echo -prijs "восемь";;
9) echo -prijs "девять";;
esac
done
echo "Цена составляет: " 'expr $thousands + $hundreds + $teens + $units'
Для будущего себя и людей, ищущих эту команду.
Я наткнулся на эту команду, просматривая список вкладок:
spellout 1.0.11: конвертировать числа в названия чисел и денежные суммы
Использование: spellout [-l lang] [-p prefix] par1 [par2...]
Параметры: n: число; n-m: диапазон; n-m~s: диапазон с шагом
Примеры: spellout 1-10 500 1000-10000~1000
spellout -l en-GB -p ordinal 1-100
spellout -l en -p ordinal-number 1-100
spellout -l en -p USD 100.45
spellout -l en -p "money USD" 100.45
Справка модуля языка: spellout -l es help
Лицензия: GNU LGPL/BSD двойная лицензия
Я выяснил, что это (вероятно) происходит от Numbertext/libnumbertext и доступно в исходниках Debian
Пример:
$ spellout 39825
тридцать девять тысяч восемьсот двадцать пять
$ spellout -l de-DE 39825
neununddreißigtausendachthundertfünfundzwanzig
$ spellout -l en-US -p "money GBP" 39825
тридцать девять тысяч восемьсот двадцать пять фунтов стерлингов
$ spellout -l de-DE -p ordinal 39825
neununddreißigtausendachthundertfünfundzwanzigste
На Ubuntu 24.04 вы можете установить и использовать его с:
sudo apt install libnumbertext-tools
/usr/lib/libnumbertext/spellout -l en 100
В вашем коде есть несколько проблем. Первая проблема в том, что вы используете одинарные кавычки, где следует использовать обратные кавычки. Вторая проблема в том, что expr
на самом деле не нужен в bash, $(())
справится с задачей. Третья проблема в том, что формула просто неправильная. Четвертая проблема – это -prijs
, как указано в комментарии. Перепишите эту часть вашего кода,
thousands="expr $price /1000"
hundreds="expr ($price - $thousands) / 100"
teens="expr ($price - $hundreds - $thousands / 10"
units="expr $price - $hundreds - $thousands - $teens"
на
thousands=$((price/1000))
hundreds=$((price%1000/100))
teens=$((price%100/10))
units=$((price%10))
где %
– это оператор остатка в bash. Попробуйте исправить остальное (например, вещи с -prijs
и последнюю строку вашего скрипта) самостоятельно.
Интересная задача. Вот мой вариант
#!/bin/bash
digits=(
"" один два три четыре пять шесть семь восемь девять
десять одиннадцать двенадцать тринадцать четырнадцать пятнадцать шестнадцать семнадцать восемьнадцать девятнадцать
)
tens=("" "" двадцать тридцать сорок пятьдесят шестьдесят семьдесят восемьдесят девяносто)
units=("" тысяча миллион миллиард триллион)
number2words() {
local -i number=$((10#$1))
local -i u=0
local words=()
local group
while ((number > 0)); do
group=$(hundreds2words $((number % 1000)) )
[[ -n "$group" ]] && group="$group ${units[u]}"
words=("$group" "${words[@]}")
((u++))
((number = number / 1000))
done
echo "${words[*]}"
}
hundreds2words() {
local -i num=$((10#$1))
if ((num < 20)); then
echo "${digits[num]}"
elif ((num < 100)); then
echo "${tens[num / 10]} ${digits[num % 10]}"
else
echo "${digits[num / 100]} сто $("$FUNCNAME" $((num % 100)) )"
fi
}
with_commas() {
# sed -r ':a;s/^([0-9]+)([0-9]{3})/\1,\2/;ta' <<<"$1"
# или, с помощью только bash
while [[ $1 =~ ^([0-9]+)([0-9]{3})(.*) ]]; do
set -- "${BASH_REMATCH[1]},${BASH_REMATCH[2]}${BASH_REMATCH[3]}"
done
echo "$1"
}
for arg; do
[[ $arg == *[^0-9]* ]] && result="NaN" || result=$(number2words "$arg")
printf "%s\t%s\n" "$(with_commas "$arg")" "$result"
done
В действии:
$ bash ./num2text.sh 9 98 987 9786 98765 987654 9876543 98765432 987654321 9876543210 98765432100 987654321000 9876543210000 98765432100000 987654321000000 1,234 x 1y z2
9 девять
98 девяносто восемь
987 девятьсот восемьдесят семь
9,786 девять тысяч семьсот восемьдесят шесть
98,765 девяносто восемь тысяч семьсот шестьдесят пять
987,654 девятьсот восемьдесят семь тысяч шестьсот пятьдесят четыре
9,876,543 девять миллионов восемьсот семьдесят шесть тысяч пятьсот сорок три
98,765,432 девяносто восемь миллионов семьсот шестьдесят пять тысяч четыреста тридцать два
987,654,321 девятьсот восемьдесят семь миллионов шестьсот пятьдесят четыре тысячи триста двадцать один
9,876,543,210 девять миллиардов восемьсот семьдесят шесть миллионов пятьсот сорок три тысячи двести десять
98,765,432,100 девяносто восемь миллиардов семьсот шестьдесят пять миллионов четыреста тридцать две тысячи сто
987,654,321,000 девятьсот восемьдесят семь миллиардов шестьсот пятьдесят четыре миллиона триста двадцать одна тысяча
9,876,543,210,000 девять триллионов восемьсот семьдесят шесть миллиардов пятьсот сорок три миллиона двести десять тысяч
98,765,432,100,000 девяносто восемь триллионов семьсот шестьдесят пять миллиардов четыреста тридцать две миллиона сто тысяч
987,654,321,000,000 девятьсот восемьдесят семь триллионов шестьсот пятьдесят четыре миллиарда триста двадцать один миллион
1,234 NaN
x NaN
1y NaN
z2 NaN
Ответ или решение
Преобразование чисел в слова: создание скрипта на Bash для Linux
В задачи программиста часто входит необходимость представлять числовые значения в текстовом формате. В данном случае мы сосредоточимся на разработке скрипта на Bash, который будет конвертировать числа в слова на голландском языке. Данный проект имеет свою специфику, включая недостаток времени и игнорирование дробных значений.
Исходные ошибки и их исправления
Ваш исходный код содержит несколько ошибок, которые необходимо исправить:
- Неправильное использование переменных: Переменные в Bash необходимо объявлять без кавычек и необходимо избегать использования
expr
. Вместо этого используйте$(())
. - Неверные математические операции: Логика вычислений в ваших выражениях не совсем верна. Кроме того, необходимо правильно открывать и закрывать скобки.
- Использование
-prijs
: Этот элемент является частью вашей программы, но в текущем контексте он неправильно применяется. Следует использовать простоecho
.
Обновленный код
Вот обновленный код, который исправляет вышеперечисленные ошибки и увеличивает ясность:
#!/bin/bash
echo "Введите цену: "
read price
# Вычисление разрядов
thousands=$((price / 1000))
hundreds=$((price % 1000 / 100))
teens=$((price % 100 / 10))
units=$((price % 10))
# Функция для преобразования чисел в слова
number_to_words() {
local number=$1
local words=""
# Тысячи
case $number in
0) words="" ;;
1) words="één" ;;
2) words="twee" ;;
3) words="drie" ;;
4) words="vier" ;;
5) words="vijf" ;;
6) words="zes" ;;
7) words="zeven" ;;
8) words="acht" ;;
9) words="negen" ;;
esac
# Добавьте множество разрядов аналогично
# [...]
echo $words
}
# Вывод преобразованных данных
echo "Цена в словах: "
echo "$(number_to_words $thousands) $(number_to_words $hundreds) $(number_to_words $teens) $(number_to_words $units)"
Обратите внимание, что функции и конструкция case
проще настроить для выполнения всех необходимых преобразований. Для полноты реализации вы можете добавить дополнительные случаи для других разрядов (десятки, сотни и тысячи), придерживаясь аналогичной структуры, чтобы предоставить правильные финальные слова для всех частей числа.
Заключение
Создание скрипта для преобразования чисел в слова может значительно улучшить функциональность ваших приложений, особенно в области, где требуется читаемость финансовой информации. Исправление возможных ошибок синтаксиса и логики в коде является важным шагом. Внедряя предложенные изменения, вы сможете получить полностью рабочий скрипт, который точно передает числовые значения в текстовом формате. В дополнение к скрипту, вы также можете использовать утилиты от сторонних разработчиков, такие как spellout
, для более сложных задач преобразования.
Надеюсь, это руководство помогло вам выявить и исправить ошибки в вашем коде, а также расширить ваши знания по работе со скриптами Bash.