[英]Concatenating digits from a string in sh
Assuming that I have a string like this one: 假设我有一个像这样的字符串:
string="1 0 . @ 1 1 ? 2 2 4"
Is it possible to concatenate digits that are next to each other? 是否可以连接彼此相邻的数字?
So that string
be like: 10 . @ 11 ? 224
所以这个string
就像: 10 . @ 11 ? 224
10 . @ 11 ? 224
10 . @ 11 ? 224
? 10 . @ 11 ? 224
?
I found only basic things how to distinguish integers from other characters and how to "connect" them. 我发现只有基本的东西如何区分整数和其他字符以及如何“连接”它们。 But I have no idea how to iterate properly. 但我不知道如何正确迭代。
num=""
for char in $string; do
if [ $char -eq $char 2>/dev/null ] ; then
num=$num$char
Here's an almost pure-shell implementation -- transforming the string into a character per line and using a BashFAQ #1 while read
loop. 这是一个几乎纯shell的实现 - 将字符串转换为每行一个字符,并while read
循环时使用BashFAQ#1 。
string="1 0 . @ 1 1 ? 2 2 4"
output=''
# replace spaces with newlines for easier handling
string=$(printf '%s\n' "$string" | tr ' ' '\n')
last_was_number=0
printf '%s\n' "$string" | {
while read -r char; do
if [ "$char" -eq "$char" ] 2>/dev/null; then # it's a number
if [ "$last_was_number" -eq "1" ]; then
output="$output$char"
last_was_number=1
continue
fi
last_was_number=1
else
last_was_number=0
fi
output="$output $char"
done
printf '%s\n' "$output"
}
To complement Charles Duffy's helpful, POSIX-compliant sh
solution with a more concise perl
alternative: 为了补充Charles Duffy有用的,符合POSIX标准的sh
解决方案 ,使用更简洁的perl
替代方案:
Note: perl
is not part of POSIX, but it is preinstalled on most modern Unix-like platforms. 注意: perl
不是POSIX的一部分,但它预装在大多数现代类Unix平台上。
$ printf '%s\n' "1 0 . @ 1 1 ? 2 2 4" | perl -pe 's/\d( \d)+/$& =~ s| ||gr/eg'
10 . @ 11 ? 224
The outer substitution, s/\\d( \\d)+/.../eg
, globally ( g
) finds runs of at least 2 adjacent digits ( \\d( \\d)+
), and replaces each run with the result of the expression ( e
) specified as the replacement string (represented as ...
here). 外部替换, s/\\d( \\d)+/.../eg
,global( g
)查找至少2个相邻数字( \\d( \\d)+
)的运行,并用结果替换每次运行表达式 ( e
)指定为替换字符串(表示为...
here)。
The expression in the inner substitution, $& =~ s| ||gr
内部替换中的表达式 , $& =~ s| ||gr
$& =~ s| ||gr
, whose result is used as the replacement string, removes all spaces from each run of adjacent digits: $& =~ s| ||gr
,其结果用作替换字符串,从每个相邻数字运行中删除所有空格:
$&
represents what the outer regex matched - the run of adjacent digits. $&
表示外部正则表达式匹配的内容 - 相邻数字的运行。 =~
applies the s
call on the RHS to the LHS, ie, $&
(without this, the s
call would implicitly apply to the entire input string, $_
). =~
将RHS上的s
调用应用于LHS,即$&
(没有这个, s
调用将隐式应用于整个输入字符串$_
)。 s| ||gr
s| ||gr
replaces all ( g
) instances of <space>
from the value of the value of $&
and returns ( r
) the result, effectively removing all spaces. s| ||gr
从$&
的值替换<space>
所有( g
)实例,并返回( r
)结果,有效地删除所有空格。
|
请注意|
is used arbitrarily as the delimiter character for the s
call, so as to avoid a clash with the customary /
delimiter used by the outer s
call. 任意地用作s
调用的分隔符,以避免与外部 s
调用使用的习惯/
分隔符发生冲突。 POSIX compliant one-liner with sed: 符合POSIX标准的单线和sed:
string="1 0 . @ 1 1 ? 2 2 4"
printf '%s\n' "$string" | sed -e ':b' -e ' s/\([0-9]\) \([0-9]\)/\1\2/g; tb'
It just iteratively removes the any space between two digits until there aren't any more, resulting in: 它只是迭代地删除两个数字之间的任何空格,直到不再有,导致:
10 . @ 11 ? 224
Here is my solution: 这是我的解决方案:
string="1 0 . @ 1 1 ? 2 2 4"
array=(${string/// })
arraylength=${#array[@]}
pattern="[0-9]"
i=0
while true; do
str=""
start=$i
if [ $i -eq $arraylength ]; then
break;
fi
for (( j=$start; j<${arraylength}; j++ )) do
curr=${array[$j]}
i=$((i + 1))
if [[ $curr =~ $pattern ]]; then
str="$str$curr"
else
break
fi
done
echo $str
done
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.