这是我使用的程序。
clear
echo enter a string
read string
length=`echo -n $string | wc -c`
v=0
cons=0
d=0
s=0
len=$length
while [ $len -gt 0 ]
do
h=`echo $string | cut -c $len`
case $h in
[AaEeIiOoUu]) v=`expr $v + 1`
;;
[BbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz]) cons=`expr $cons + 1`
;;
[0-9]) d=`expr $d + 1`
;;
' ') s=`expr $s + 1 `
;;
esac
len=`expr $len - 1 `
done
spl=`expr $len - $v - $cons - $d - $s`
echo "vowels = $v"
echo "consonants = $cons"
echo "digits = $d"
echo "spaces = $s"
echo "special character = $spl"
该程序计算除特殊字符外的所有其他类型的字符。即使输入值中有特殊字符,输出也会显示负值。如何修改程序以使其在输入中显示正确数量的特殊字符?
答案 0 :(得分:6)
虽然你的脚本在技术上(几乎)是正确的,但它不是很漂亮(在视觉和代码美感方面)。
您的版本未按预期工作的原因@devnull已经指出,但还有另一个错误,我将进一步解释。
由于您使用的是bash
,因此您可以用更惯用,可读和更短的方式重写整个内容。
以下是您的脚本的重写版本(评论和解释如下):
#!/bin/bash
clear
IFS= read -p "enter a string: " string
for ((i = 0; i < ${#string}; i++)); do
case "${string:$i:1}" in
[AaEeIiOoUu]) ((vowels++)) ;;
[[:alpha:]]) ((consonants++)) ;;
[[:digit:]]) ((digits++)) ;;
[[:space:]]) ((whitespace++)) ;;
*) ((others++)) ;;
esac
done
echo "vowels = ${vowels-0}"
echo "consonants = ${consonants-0}"
echo "digits = ${digits-0}"
echo "whitespace = ${whitespace-0}"
echo "other characters = ${others-0}"
首先,为了便于阅读,您应该始终缩进代码块(if
构造,循环,切换(case
)语句,...),例如
while [ $len -gt 0 ]; do
do_stuff
done
由于您使用的是bash
,read
能够为您显示提示,因此不需要额外的echo
。此外,除非您将read
设置为空字符串,否则IFS
会删除前导空格和尾随空格,从而导致计算错误:
IFS= read -p "this is my prompt: " string
您可以使用参数扩展来获取字符串的长度,并使用for循环一次切出一个字符,去除不必要的cut
并避免一个子壳。
# ${#string} = length of $string
for ((i = 0; i < ${#string}; i++)); do
c=${string:$i:1} # c is set to the character at position $i in string $string
done
首先,您的辅音语句仍然包含Ii
的匹配项。从技术上讲,它无关紧要,因为你无法从元音匹配中删除,但如果这是一个分配,你可能想删除它。
话虽如此,你可以使用短字符类来提高可读性:
[AaEeIiOoUu]) vowel_stuff ;;
[a-zA-Z]) consonant_stuff ;; # vowels already matched above, so superfluous characters don't matter here
为了让您的生活更轻松,您可以使用所谓的字符类,例如
[:digit:] = [0-9]
[:space:] = tabs, newline, form feed, carriage return, space
等。 请注意,您当前的语言环境会影响某些字符类。
只需使用switch语句中的默认大小写来计算它们,然后就可以跳过计算它们了:
case ... in
vowels) handle_vowel ;;
[...]
*) handle_other_character ;;
esac
使用参数扩展,您还可以摆脱使用0
初始化变量,如果未设置变量,您可以即时将变量扩展为0
,即它们没有增加在循环中。
除非您编写的代码必须是超级可移植的并且必须适用于各种旧shell,否则请使用$()
语法代替``
。
与上面相同,除非你真的需要它,你可以使用(( ))
作为算术表达式,例如。
a=5
((a = a + 10)) # or even ((a += 10))
# $a is now 15
Google和Advanced Bash-Scripting Guide以及Greg's Wiki的bash
部分是您的朋友。
答案 1 :(得分:5)
您在计算spl
时使用了错误的变量。使用len
显然是错误的,因为你在循环中递减它,并且当循环完成时它变为0
。
而不是说:
spl=`expr $len - $v - $cons - $d - $s`
说:
spl=`expr $length - $v - $cons - $d - $s`