Bir dizedeki nokta ile ayrılmış öğelerin ters sırası


14

Gibi bir giriş dizesi var:

arg1.arg2.arg3.arg4.arg5

İstediğim çıktı:

arg5.arg4.arg3.arg2.arg1

Her zaman 5 arg değil, 2 ila 10 olabilir.

Bunu bir bash betiğinde nasıl yapabilirim?

Yanıtlar:


22
  • tr+ tac+ Kombinasyonunu kullanmapaste

    $ tr '.' $'\n' <<< 'arg1.arg2.arg3.arg4.arg5' | tac | paste -s -d '.'
    arg5.arg4.arg3.arg2.arg1
  • Hala bash'ı tercih ediyorsanız, bu şekilde yapabilirsiniz,

    IFS=. read -ra line <<< "arg1.arg2.arg3.arg4."
    let x=${#line[@]}-1; 
    while [ "$x" -ge 0 ]; do 
          echo -n "${line[$x]}."; 
          let x--; 
    done
  • Kullanmak perl,

    $ echo 'arg1.arg2.arg3.arg4.arg5' | perl -lne 'print join ".", reverse split/\./;'
    arg5.arg4.arg3.arg2.arg1

2
Bah, ben sadece Perl çözümünü
gönderecektim

10

Biraz sakıncası yoksa python:

".".join(s.split(".")[::-1])

Misal:

$ python3 -c 's="arg1.arg2.arg3.arg4.arg5"; print(".".join(s.split(".")[::-1]))'
arg5.arg4.arg3.arg2.arg1
  • s.split(".").ayrılmış alt dizeler içeren bir liste oluşturur, listeyi [::-1]tersine çevirir ve ".".join()ters listenin bileşenlerini ile birleştirir ..

5

Tek bir sedçağrı ile yapabilirsiniz :

sed -E 'H;g;:t;s/(.*)(\n)(.*)(\.)(.*)/\1\4\5\2\3/;tt;s/\.(.*)\n/\1./'

bu, desen alanında önde gelen bir yeni satır elde etmek için tutma arabelleğini kullanır ve yeni satır artık izleyen noktadan sonra, nokta noktasını model uzayından kaldırarak yeni satırı bir nokta ile değiştirene kadar permütasyon yapmak için kullanır.
BRE ve biraz farklı regex ile:

sed 'H
g
:t
s/\(.*\)\(\n\)\(.*\)\(\.\)\(.*\)/\1\4\5\2\3/
tt
s/\(\.\)\(.*\)\n/\2\1/'

Giriş birden fazla satırdan oluşuyorsa ve her satırdaki sıralamayı tersine çevirmek istiyorsanız:

sed -E 'G;:t;s/(.*)(\.)(.*)(\n)(.*)/\1\4\5\2\3/;tt;s/(.*)\n(\.)(.*)/\3\2\1/'

3

SED çözümü:

sed 's/\./\n/g' yourFile | tac | sed ':a; $!{N;ba};s/\n/./g'

3

İle zsh:

$ string=arg1.arg2.arg3.arg4.arg5
$ printf '%s\n' ${(j:.:)${(Oas:.:)string}}
arg5.arg4.arg3.arg2.arg1

Boş elemanları korumak için:

$ string=arg1.arg2.arg3.arg4..arg5.
$ printf '%s\n' ${(j:.:)"${(@Oas:.:)string}"}
.arg5..arg4.arg3.arg2.arg1
  • s:.:: bölünmüş .
  • Oa: Ters sıralama dizisi bir rray indisi o order
  • j:.:: katılın ..
  • @: "$@"çift ​​tırnak içine alındığında genişletme gibi genişleme boş kaldırma işleminden geçmez.

POSIX (veya bash) eşdeğeri aşağıdaki gibi olabilir:

string=arg1.arg2.arg3.arg4..arg5.

IFS=.; set -f
set -- $string$IFS # split string into "$@" array
unset pass
for i do # reverse "$@" array
  set -- "$i" ${pass+"$@"}
  pass=1
done
printf '%s\n' "$*" # "$*" to join the array elements with the first
                   # character of $IFS

( zsh( shemülasyonda) yashve bazı pdkshtabanlı kabukların, bu nedenle $IFSalan sınırlayıcı yerine alan ayırıcısı olarak işlem görmeleri açısından POSIX olmadığını unutmayın )

Burada verilen diğer bazı çözümler farklıdır nerede satır karakteri tedavi etmez (ve söz konusu zshher iki NULL bir) özel olarak, yani $'ab.cd\nef.gh'için geri alınması $'gh.cd\nef.ab'değil, $'cd.ab\ngh.ef'ya da $'gh.ef.cd.ab'.


Sorun IFS="."; set -f; set -- $string$IFS; for i; do rev="$i$IFS$rev"; done; printf '%s\n' "${rev%$IFS}"nedir?

@BinaryZebra Hiçbir şey ( for i; dobildiğim tüm POSIX kabukları tarafından desteklense bile POSIX (henüz) dışında ). Sadece bu çözüm, doğrudan zshPOSIX operatörleri kullanarak bir dizinin doğrudan dizisidir (dizi, ters dizi, birleştirme dizi elemanları). (Ben değiştim string=$string$IFS; set -- $stringiçin set -- $string$IFS, o kabukları tutarlı iş gibi görünüyor olarak sayesinde).
Stéphane Chazelas

2

Rahul'ın zaten (diğerlerinin yanı sıra) yerli bir bash çözümü gönderdiğini görüyorum , ki bu ilk bulduğumdan daha kısa bir versiyon:

function reversedots1() (
  IFS=. read -a array <<<"$1"
  new=${array[-1]}
  for((i=${#array[*]} - 2; i >= 0; i--))
  do
    new=${new}.${array[i]}
  done
  printf '%s\n' "$new"
)

ama orada duramadım ve özyinelemeli bash merkezli bir çözüm yazma gereğini hissettim:

function reversedots2() {
  if [[ $1 =~ ^([^.]*)\.(.*)$ ]]
  then
    printf %s $(reversedots2 "${BASH_REMATCH[2]}") . "${BASH_REMATCH[1]}"
  else
    printf %s "$1"
  fi
}

2

Bir awkcevap görmedim , işte bir tane:

 echo 'arg1.arg2.arg3' | awk -F. '{for (i=NF; i>0; --i) printf "%s%s", (i<NF ? "." : ""), $i; printf "\n"}'

1

Saf Bash, girişte sondaki dönemi gerektirir:

echo 'foo.bar.baz.' | ( while read -d . f;do g="$f${g+.}$g" ;done;echo "$g" )

printf %s "$g"Noktalı öğelerden herhangi biri kısa çizgi ile başlayabilirse kullanın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.