Reverse four length of letters with sed in unix

2020-08-26 03:22发布

How can I reverse a four length of letters with sed?

For example:

the year was 1815.

Reverse to:

the raey was 5181.

This is my attempt:

cat filename | sed's/\([a-z]*\) *\([a-z]*\)/\2, \1/'

But it does not work as I intended.

标签: bash unix sed
5条回答
一纸荒年 Trace。
2楼-- · 2020-08-26 03:57

Following awk may help you in same. Tested this in GNU awk and only with provided sample Input_file

echo "the year was 1815." |
awk '
function reverse(val){
  num=split(val, array,"");
  i=array[num]=="."?num-1:num;
  for(;i>q;i--){
    var=var?var array[i]:array[i]
};
  printf (array[num]=="."?var".":var);
  var=""
}
{
for(j=1;j<=NF;j++){
  printf("%s%s",j==NF||j==2?reverse($j):$j,j==NF?RS:FS)
}}'
查看更多
smile是对你的礼貌
3楼-- · 2020-08-26 03:57

This might work for you (GNU sed):

sed -r '/\<\w{4}\>/!b;s//\n&\n/g;s/^[^\n]/\n&/;:a;/\n\n/!s/(.*\n)([^\n])(.*\n)/\2\1\3/;ta;s/^([^\n]*)(.*)\n\n/\2\1/;ta;s/\n//' file

If there are no strings of the length required to reverse, bail out.

Prepend and append newlines to all required strings.

Insert a newline at the start of the pattern space (PS). The PS is divided into two parts, the first line will contain the current word being reversed. The remainder will contain the original line.

Each character of the word to be reversed is inserted at the front of the first line and removed from the original line. When all the characters in the word have been processed, the original word will have gone and only the bordering newlines will exist. These double newlines are then replaced by the word in the first line and the process is repeated until all words have been processed. Finally the newline introduced to separate the working line and the original is removed and the PS is printed.

N.B. This method may be used to reverse strings of varying string length i.e. by changing the first regexp strings of any number can be reversed. Also strings between two lengths may also be reversed e.g. /\<w{2,4}\>/ will change all words between 2 and 4 character length.

查看更多
我想做一个坏孩纸
4楼-- · 2020-08-26 04:06

It's a recurrent problem so somebody created a bash command called "rev".

echo "$(echo the | rev) $(echo year | rev) $(echo was | rev) $(echo 1815 | rev)".

OR

echo "the year was 1815." | rev | tr ' ' '\n' | tac | tr '\n' ' '

查看更多
老娘就宠你
5楼-- · 2020-08-26 04:10

Possible shortest sed solution even if a four length of letters contains _s.

sed -r 's/\<(.)(.)(.)(.)\>/\4\3\2\1/g'
查看更多
叼着烟拽天下
6楼-- · 2020-08-26 04:13

not sure it is possible to do it with GNU sed for all cases. If _ doesn't occur immediately before/after four letter words, you can use

sed -E 's/\b([a-z0-9])([a-z0-9])([a-z0-9])([a-z0-9])\b/\4\3\2\1/gi'

\b is word boundary, word definition being any alphabet or digit or underscore character. So \b will ensure to match only whole words not part of words

$ echo 'the year was 1815.' | sed -E 's/\b([a-z0-9])([a-z0-9])([a-z0-9])([a-z0-9])\b/\4\3\2\1/gi'
the raey was 5181.
$ echo 'two time five three six good' | sed -E 's/\b([a-z0-9])([a-z0-9])([a-z0-9])([a-z0-9])\b/\4\3\2\1/gi'
two emit evif three six doog

$ # but won't work if there are underscores around the words
$ echo '_good food' | sed -E 's/\b([a-z0-9])([a-z0-9])([a-z0-9])([a-z0-9])\b/\4\3\2\1/gi'
_good doof


tool with lookaround support would work for all cases

$ echo '_good food' | perl -pe 's/(?<![a-z0-9])([a-z0-9])([a-z0-9])([a-z0-9])([a-z0-9])(?!=[a-z0-9])/$4$3$2$1/gi'
_doog doof

(?<![a-z0-9]) and (?!=[a-z0-9]) are negative lookbehind and negative lookahead respectively

Can be shortened to

perl -pe 's/(?<![a-z0-9])[a-z0-9]{4}(?!=[a-z0-9])/reverse $&/gie'

which uses the e modifier to place Perl code in substitution section. This form is suitable to easily change length of words to be reversed

查看更多
登录 后发表回答