我正在尝试编写一个代码,将任何给定的单词转换为其数字名称。
例如:国际化= i18n(第一个字符+中间的字符数+最后一个字符)
我找到了如何查找第一个和最后一个字符,并且知道如何查找数字部分,但我不知道如何将数字放在第一个和最后一个字符之间。
我用来获取数字部分的代码是:
cut -c 2- | rev | cut -c 2- | rev | tr -d [:space:]| wc -c
我用来获取第一个和最后一个字符的代码:
awk -F "" '{print $1,$NF}'
答案1
尽管我发现使用awk
空字段分隔符有些“创新”,但我认为最简单的解决方案只是您的解决方案的一个小扩展:
awk -F "" '{print $1 (NF-2) $NF}'
当然,这只适用于三个或更多字母的单词。处理一般情况:
awk -F "" '{if (NF>2) print $1 (NF-2) $NF; else print $0}'
作为解释:
- 通过使用 将字段分隔符设置为“空”
-F ""
,输入将在每个字符后拆分为多个字段,即输入的每个字符都被视为一个单独的“字段”,可通过$n
in访问的单独“字段”awk表达式(与n是范围从 1 到NF
) 的字段编号。顺便说一句,GNU Awk 用户指南明确指出提供此类用例作为示例,所以我纠正了我之前对使用空 FS 的担忧。不过,请注意手册中说“这是一个常见的扩展;POSIX 标准并未指定它”。 if
字段数(即此处的字符数)大于 2,则打印第一个字段/字符 ($1
)、求值表达式 (NF-2
)(相当于第一个和最后一个之间的字符数)以及最后一个字段/字符($NF
)。请注意,print
此处使用的调用不会在各个输出标记之间产生空格;仅当用逗号而不是空格分隔参数时才会发生这种情况(请参阅例如 GNU Awk 用户指南)。else
只需打印整个输入表达式,可以通过以下方式访问$0
请注意,如果我们错误地输入了两个字符的输入,例如 at
,对于第一个代码示例,我们会得到不需要的(但形式上正确的)输出a0t
(因为在这种情况下,第一个和最后一个之间有零个字符)。
另请注意,这一点很重要,如果您为此调用提供包含前导或尾随空格的字符串awk
(例如 in )echo " hello" | awk <etc.>
,那么该前导/尾随空格将被视为第一个/最后一个字符,从而产生不需要的行为!
答案2
在 ksh93、bash 或 zsh 中:
numeronym() {
(( ${#1} > 2 )) || return
printf '%s%d%s\n' "${1:0:1}" "$(( ${#1} - 2 ))" "${1: -1:1}"
}
这通过打印第一个字母(字符数减 2)和最后一个字母来处理第一个(唯一)参数。
答案3
另一个 awk 解决方案:
awk '{l=length($1); print substr($1,1,1) l-2 substr($1,l,1)}'
l=length($1)
- 将l
变量设置为字符串的长度(假设输入字符串位于第一列并且不包含空格)substr($1,1,1)
- (列#、起始点、结束点)因此打印第 1 列,从位置 1 开始,并打印 1 个字符。l-2
- 字符串长度减 2substr($1,l,1)
- 从位置l
(字符串长度)开始打印第 1 列并打印 1 个字符。
答案4
可移植到许多 shell:
a=internationalization;
if [ "${#a}" -gt 2 ]; then
a="${a%"${a#?}"}$((${#a}-2))${a#"${a%?}"}";
fi
printf '%s\n' "${a}"
作为一个函数(可移植性稍差):
numeronym() { a="$1";
if [ "${#1}" -gt 2 ]; then
a="${a%"${a#?}"}$((${#a}-2))${a#"${a%?}"}";
fi;
printf '%s\n' "${a}";
}
称其为:
$ numeronym internationalization
i18n
如果必须是 awk:
$ echo internationalization |
awk '{ print (NF>2) ? $1 NF-2 $NF : $0 }' FS=''
i18n