反转字符串中字符的顺序


Answers:


29

简单:

var="12345"
copy=${var}

len=${#copy}
for((i=$len-1;i>=0;i--)); do rev="$rev${copy:$i:1}"; done

echo "var: $var, rev: $rev"

输出:

$ bash rev
var: 12345, rev: 54321

+1可以很容易地扩展ascii hex为例如反向字节。
artless噪音

我添加了一个改进的答案,因为我的编辑未被接受(包括POSIX解决方案)。

172

我知道您说过“没有第三方工具”,但是有时候工具显然是正确的工具,而且默认情况下它已安装在大多数linux系统上:

[madhatta@risby tmp]$ echo 12345|rev
54321

1
但不适用于嵌入式发行版,例如OpenWRT:-/
bk138

1
rev <<< 12345使用bash,zsh和ksh。(不是破折号或csh。)
loxaxs

1
我听到了,但是请尝试echo '\xff' |rev。我从来没有说过这样做echo -e会行得通,所以在不行的时候让我over之以鼻似乎有点苛刻。
MadHatter

如果字符串包含换行符,则此方法无效。rev在每行上独立起作用,并且似乎没有任何命令行选项可以对此进行修改。此外,如@Equidamoid的示例所示(顺便说一下,这与无关echo -e),它假定字符串是正确编码的字符序列。如果您需要按字节反转某些内容(例如,如果您不处理二进制数据而不是实际文本),则此解决方案无效。[注意:为解决格式问题,我删除了此评论并重新发布。抱歉,可能会产生幻影通知。]
greatBigDot

12

rev | tail -r(BSD)或rev | tac(GNU)也会反转行:

$ rev <<< $'12\n34' | tail -r
43
21
$ rev <<< $'12\n34' | gtac
43
21

如果LC_CTYPE为C,则rev反转多字节字符的字节:

$ LC_CTYPE=C rev <<< あの
��め�
$ export LC_ALL=C; LC_ALL=en_US.UTF-8 rev <<< あの
のあ

+1提及tac。请注意,tac\n使用该-s选项相比,它支持传递不同的定界符。
Bart Kleijngeld

12

假设变量“ var”的值为“ 123”

var="123"

反转字符串并将其存储在新变量“ rav”中:

rav=$(echo $var | rev)

您会通过echo看到'rav'的值为'321'。

echo $rav

8

一个bash解决方案,改进了@osdyng答案(我的编辑不被接受):

var="12345"     rev=""

for(( i=0 ; i<${#var} ; i++ )); do rev="${var:i:1}$rev"; done

echo "var: $var, rev: $rev"

或更简单的(bash)循环:

var=$1   len="${#var}"   i=0   rev=""

while (( i<len )); do rev="${var:i++:1}$rev"; done

echo "var: $var, rev: $rev"

POSIX解决方案:

var="12345"     rev=""    i=1

while  [ "$i" -le "${#var}" ]
do     rev="$(echo "$var" | awk -v i="$i" '{print(substr($0,i,1))}')$rev"
       : $(( i+=1 ))
done

echo "var: $var, rev: $rev"

注意:这适用于多字节字符串。剪切解决方案仅适用于ASCII(1字节)字符串。


如果仍然要依赖awk,为什么不只运行一次而不是循环运行呢?awk '{for(i=length($0);i;i--)printf "%s",substr($0,i,1); print ""}'甚至awk '{for(i=length($0);i;i--)x=x substr($0,i,1); print x}'
ghoti

6

这会反转字符串“ in place”:

a=12345
len=${#a}
for ((i=1;i<len;i++)); do a=$a${a: -i*2:1}; done; a=${a:len-1}
echo $a

或者第三行可能是:

for ((i=0;i<len;i++)); do a=${a:i*2:1}$a; done; a=${a:0:len}

要么

for ((i=1;i<len;i++)); do a=${a:0:len-i-1}${a: -i:i+1}${a:len-i-1:1}; done

6

对于那些没有rev(推荐)的用户,有以下简单的awk解决方案,该解决方案将null字符串上的字段拆分(每个字符都是单独的字段)并反向打印:

awk -F '' '{ for(i=NF; i; i--) printf("%c", $i); print "" }'

上面的awk代码符合POSIX。由于可以确保在每个POSIX兼容操作系统上都使用兼容的awk实现,因此不应将解决方案视为“第三方”。与纯POSIX sh(或bash)解决方案相比,此代码可能更简洁明了。

(;我不知道您是否将-F的空字符串视为正则表达式...;)


5

反转字符串的一些简单方法

echo '!!!esreveR si sihT' | grep -o . | tac | tr -d '\n' ; echo

echo '!!!esreveR si sihT' | fold -w 1 | tac | tr -d '\n' ; echo

转换为十六进制值然后反转

echo '!!!esreveR si sihT' | xxd -p | grep -o .. | tac | xxd -r -p ; echo

echo '!!!esreveR si sihT' | xxd -p | fold -w 2 | tac | xxd -r -p ; echo

4

如果 var=12345

for((i=0;i<${#var};i++)); do rev="$rev${var:~i:1}"; done

c=$var; while [ "$c" ]; do rev=$rev${c#"${c%?}"}; c=${c%?}; done

echo "var: $var, rev: $rev"

运行:

$ rev
var: 12345, rev: 54321

3

这当然可以缩短,但是应该易于理解:最后print添加了换行符。

echo 12345 | awk '{for (i = length($0); i > 0; i--) {printf("%s", substr($0, i, 1));} print "";}'

3

似乎没有人发布过sed解决方案,所以这里有一个可以在非GNU sed中使用的解决方案(因此,我不认为它是“第三方”)。它确实使用正则表达式捕获单个字符.,但这是唯一的regex。

分两个阶段:

$ echo 123456 | sed $'s/./&\\\n/g' | sed -ne $'x;H;${x;s/\\n//g;p;}'
654321

这使用bash格式替换在脚本中包含换行符(因为标记了问题 )。它的工作原理是先将输入字符串每个字符分成一行,然后将每个字符插入保持缓冲区的开头。

  • x 交换保留空间和模式空间,然后
  • H H将(当前)模式空间附加到保持空间。

因此,对于每个字符,我们将其放置到容纳空间中,然后将旧的容纳空间附加到其上,从而反转输入。最后的命令删除换行符以重建原始字符串。

这适用于任何单个字符串,但是它将多行输入连接为单个输出字符串。


0

这是另一个更简单的awk解决方案:

awk 'BEGIN{FS=""} {for (i=NF; i>0; i--) s=s $i; print s}' <<< '123456'

654321

-1

读单词

reve=`echo "$word" | awk '{for(i=length($0); i>0;i--) printf (substr($0,i,1));}'`
echo  "$reve"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.