反转shell中的单词

时间:2017-12-05 16:22:37

标签: linux string shell awk

任务是在具有5个或更少字符的单词中反转所有字母(a-zA-Z)。

编辑:让我们假设单词是一个不间断的英文字母序列。

(字母:ASCII范围A-Z&& a-z)

示例:

输入:"One ring to rule them all, one ring to find them, One ring to bring them all and in the darkness bind them."

输出:"enO gnir ot elur meht lla, eno gnir ot dnif meht, enO gnir ot gnirb meht lla dna ni eht darkness dnib meht."

我已经能够编写这个脚本了,但是它用带有特殊字符的单词来翻译,例如{,。},它们不应该被反转。

#!/bin/bash

    word_length=0
    touch tmp 

    for word in $(cat ./TEXT)
    do
            word_length=$(echo -n $word | wc -c )
            if [ $word_length -le 5 ] 
            then
                    echo -n $word | rev >> tmp 
                    echo -n " " >> tmp 
            else
                    echo -n $word >> tmp 
                    echo -n " " >> tmp 
            fi
    done

    cat tmp > TEXT
    echo " " >> TEXT
    rm -rf tmp

此脚本的输出: "enO gnir ot elur meht ,lla eno gnir ot dnif ,meht enO gnir ot gnirb meht lla dna ni eht darkness dnib .meht"

您可以看到{,。}位于错误的位置。

6 个答案:

答案 0 :(得分:2)

您可以使用此awk代码:

awk 'function revw(wrd) {
   if (wrd ~ /[^a-zA-Z]+[a-zA-Z]+$/ || length(wrd) > 5)
      return wrd
   nw = wrd
   sub(/^[a-zA-Z]+/, "", nw)
   sub(/[^a-zA-Z]+$/, "", wrd)
   rw = ""
   for (j=length(wrd); j>0; j--)
      rw = rw substr(wrd, j, 1)
   return rw nw
}
{
   line = ""
   for (i=1; i<=NF; i++)
      line = line revw($i) (i==NF ? "" : OFS)
   print line
}' file

enO gnir ot elur meht lla, eno gnir ot dnif meht, enO gnir ot gnirb meht lla dna ni eht darkness dnib meht.

答案 1 :(得分:1)

for word in $(cat ./TEXT), 看起来你可能会迭代输入的单词, 但是Bash对单词的定义与你预期的不同。 在上面的陈述中, Bash执行分词, 但这只是意味着按IFS的值进行分割。 默认情况下,此值是空白字符序列。 这意味着标点符号将成为单词的一部分。

  

任务是在具有5个或更少字符的单词中反转所有字母(a-zA-Z)。

对于强大的解决方案, 考虑这个算法:

  • word初始化为空字符串
  • 对于输入中的每个字符c
  • 如果c是一封信,请将其附加到word
  • 否则:
    • 如果word超过4个字符,请将其打印
    • 如果word不为空,则将其反转
    • word重置为空
    • 打印c
  • 循环后,打印word,以确保打印出最后一个单词

使用纯Bash:

#!/usr/bin/env bash

s=$(cat ./TEXT)

print_reverse() {
    local w=$1
    local i
    reversed=
    for ((i = 0; i < ${#w}; i++)); do
        reversed=${w:i:1}$reversed
    done
    printf "$reversed"
}

print_word() {
    local w=$1
    if [ ${#w} -gt 4 ]; then
        printf "$w"
    elif [ "$w" ]; then
        print_reverse "$w"
    fi
}

word=
for ((i = 0; i < ${#s}; i++)); do
    c=${s:i:1}
    case "$c" in
        [a-zA-Z]) word=$word$c ;;
        *)
            print_word "$word"
            word=
            printf "$c"
            ;;
    esac
done

print_word "$word"

答案 2 :(得分:0)

您必须将.,与您的单词分开。 你可以:

  1. 使用cat ./TEXT更改第一个sed -r 's/([,.])/ \1/g' ./TEXT,在这些字符
  2. 之前添加空格
  3. 然后当输出完成时,反向sed sed -r 's/ ([,.])/\1/g' ./TEXT删除之前添加的空白区域(在你的例子中,你的TEXT文件有一个逐字逐句,但我接受了这个假设,你将会纠正这个)
  4. 但是,这将仅限于像,.':;这样的sed中放入的字符,如果出现新字符,则必须更改脚本

    除此之外,为什么限制5个字符来反转一个单词?在你的例子中,黑暗并没有因此而逆转。

答案 3 :(得分:0)

另一个gawk

gawk -v RS='[^a-zA-Z]' 'function rev(x,rx) {n=split(x,a,"");
                                           while(n) rx=rx a[n--];
                                           return rx}

             {printf "%s", (length()>5?$0:rev($0)) RT}' file


enO gnir ot elur meht lla, eno gnir ot dnif meht, enO gnir ot gnirb meht lla dna ni eht darkness dnib meht.

答案 4 :(得分:0)

另一种bash方法,请注意此代码会将don't中的撇号转换为tnod': -

while read line
do
        printf "$line\n"
        for word in $line
        do
                for (( i = ${#word}; i >= 0; i-- ))
                do
                        if [[ "${word:$i:1}" =~ '[[:alpha:]]' ]]
                        then
                                printf "${word:$i:1}"
                        else
                                symb="${word:$i:1}"
                        fi
                done
                printf "${symb} "
        done
        printf "\n"
done < TEXT

答案 5 :(得分:0)

使用perl

$ cat ip.txt
"One ring to rule them all,
one ring to find them,
One ring to bring them all and in the darkness bind them."
O'Donnell 1234 there's pre-existing

$ perl -F'/([^a-z])/i' -ane '
          print map {$_ = length()<6 && /[a-z]/i ? reverse : $_} @F' ip.txt
"enO gnir ot elur meht lla,
eno gnir ot dnif meht,
enO gnir ot gnirb meht lla dna ni eht darkness dnib meht."
O'Donnell 1234 ereht's erp-existing
  • -F'/([^a-z])/i'使用非字母作为字段分隔符,使用()表示字段分隔符也会与字段一起保存在@F数组中
  • map用于转换数组的每个元素
  • length()<6 && /[a-z]/i条件选择小于长度为6的单词并忽略字段分隔符
  • reverse将在标量上下文中反转字符串
  • 最后打印更改的数组