Bagaimana cara menyisipkan spasi setiap empat karakter dalam garis panjang?

30

Saya memiliki garis panjang yang ingin saya sisipkan spasi setiap 4 karakter, pada satu baris teks padat untuk membuatnya lebih mudah dibaca, apa cara paling sederhana untuk melakukan ini? juga saya harus dapat memasukkan saluran dari pipa. misalnya

echo "foobarbazblargblurg" | <some command here>

memberi

foob arba zbla rgbl urg
xenoterracide
sumber

Jawaban:

54

Gunakan sed sebagai berikut:

$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
dogbane
sumber
1
Mengutuk yang begitu dekat dengan sedaku mencoba dulu aku bisa menendang diriku sendiri.
xenoterracide
7
Hanya ingin tahu, apa yang '&' capai? Oh, itu adalah standin untuk 'hal yang baru saja cocok'. Saya konyol.
Mahakuasa
1
Perlu dicatat bahwa ini menambahkan spasi di bagian akhir juga jika ada satu karakter lagi dalam string, yang mungkin tidak diinginkan
Anubis
@Anubis's/.\{4\}/& /g;s/ $//'
wieczorek1990
21

Anda dapat menggunakan contoh sederhana berikut ini:

$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
kenorb
sumber
Sangat bagus ... Saya pikir ini bahkan lebih baik daripada sedjawabannya. Saya tidak tahu tentang foldsebelumnya.
Wildcard
1
Sayangnya, dengan versi GNU foldsaat ini, tidak berfungsi dengan karakter multi-byte (seperti echo €€€€€€€€ | fold -w4 | paste -sd' ' -pada UTF-8).
Stéphane Chazelas
3

Berikut ini contoh penggunaan grepdan xargs:

$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl
kenorb
sumber
xargsberjalan echosecara default, jadi itu tidak akan berfungsi dengan kata-kata seperti -nenatau yang mengandung garis miring terbalik tergantung pada echoimplementasinya. Anda akan melihat karakter garis ganjil sesekali juga jika xarg berjalan lebih dari satu echo. Lebih baik untuk pipa paste -sd ' ' -. Perhatikan bahwa -oini bukan opsi standar.
Stéphane Chazelas
3

Dalam bash saja, tidak ada perintah eksternal:

str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"

atau sebagai versi pipa satu baris:

echo foobarbazblargblurg | 
  { IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }

Cara kerjanya adalah mengonversi setiap karakter string menjadi "(.)" Untuk pencocokan dan tangkapan regex =~, kemudian hanya mengeluarkan ekspresi yang diambil dari BASH_REMATCH[]array, dikelompokkan sesuai kebutuhan. Ruang depan / belakang / tengah dipertahankan, hapus tanda kutip "${BASH_REMATCH[@]:1}"untuk menghilangkannya.

Di sini dibungkus dalam suatu fungsi, yang ini akan memproses argumennya atau membaca stdin jika tidak ada argumen:

function fmt4() {
  while IFS= read -r str; do
    [[ $str =~ ${str//?/(.)} ]]
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
  done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}

$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg 

Anda dapat dengan mudah mengukur parameter hitungan untuk menyesuaikan string format yang sesuai.

Sebuah ruang tambahan ditambahkan, gunakan dua printfs bukan satu jika itu masalah:

printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"

Yang pertama printfmencetak (hingga) 4 karakter pertama, yang kedua secara kondisional mencetak yang lainnya (jika ada) dengan ruang utama untuk memisahkan grup. Tes ini untuk 5 elemen bukan 4 untuk memperhitungkan elemen nol.

Catatan:

  • shell printf's %cdapat digunakan sebagai pengganti %s, %c(mungkin) membuat maksud lebih jelas, tapi itu bukan multi-byte karakter aman. Jika versi bash Anda mampu, di atas semua karakter multi-byte aman.
  • shell printfmenggunakan kembali format string-nya hingga kehabisan argumen, jadi ia hanya melahap 4 argumen sekaligus, dan menangani argumen trailing (jadi tidak perlu case tepi, tidak seperti beberapa jawaban lain di sini yang bisa dibilang salah)
  • BASH_REMATCH[0] adalah seluruh string yang cocok, jadi hanya output yang dimulai dari indeks 1
  • gunakan printf -v myvar ...sebagai gantinya untuk menyimpan ke variabel myvar(tunduk pada perilaku read-loop / subshell yang biasa)
  • tambahkan printf "\n"jika diperlukan

Anda dapat membuat cara di atas berfungsi zshjika Anda menggunakan array match[]sebagai ganti BASH_REMATCH[], dan kurangi 1 dari semua indeks karena zshtidak mempertahankan elemen 0 dengan seluruh kecocokan.

mr.spuratic
sumber
3

Dengan zshhanya:

str=foobarbazblargblurg

set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }

Atau

printf '%s%s%s%s ' ${(s::)str}

ksh93hanya dengan :

printf '%s\n' "${str//????/\0 }"

Hanya dengan shell POSIX saja (juga menghindari ruang tambahan jika panjang input adalah kelipatan 4):

out=
while true; do
  case $str in
    (?????*)
      new_str=${str#????}
      out=$out${str%"$new_str"}' '
      str=$new_str
      ;;
    (*)
      out=$out$str
      break
  esac
done
printf '%s\n' "$out"

Nah, itu untuk karakter . Jika Anda ingin melakukannya di cluster grapheme (misalnya, untuk memecah Stéphane, ditulis sebagai $'Ste\u0301phane', seperti Stép hanedan tidak Ste phan e), dengan zsh:

set -o rematchpcre
str=$'Ste\u301phane' out=
while [[ $str =~ '(\X{4})(.+)' ]] {
  out+="$match[1] " str=$match[2]
}
out+=$str
printf '%s\n' $out

Dengan ksh93, Anda dapat memecah dengan lebar layar juga, yang akan bekerja untuk itu di Stéphaneatas, tetapi juga bisa membantu ketika beberapa jenis karakter lain dari lebar nol atau lebar ganda terlibat:

str=$'Ste\u301phane' out=
while
  start=${ printf %L.4s. "$str"; }
  start=${start%.}
  [ "$start" != "$str" ]
do
  out+="$start " str=${str#"$start"}
done
out+=$str
printf '%s\n' "$out"
Stéphane Chazelas
sumber
2

Saya akan menjawab dengan hanya memasukkan spasi sesuai kebutuhan sehingga spasi muncul setidaknya setelah setiap 4 karakter pada satu baris; tidak yakin ke arah mana Anda ingin menangani kasus ini. Misalnya, diberi input "aa bbccdd", Anda akan mendapatkan output "aa bbcc dd" daripada "aa b bccd d".

Saya menggunakan Perl untuk lookahead, tapi saya tidak terlalu akrab dengan Perl secara umum, jadi mungkin diperlukan penyesuaian:

$ echo "foobarbazblargblurg" | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
foob arba zbla rgbl urg

$ echo 'aa bbccdd' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
aa bbcc dd
# not 'aa b bccd d'!

$ echo 'some input' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
some inpu t
# not 'some  inp ut'!

$ echo $'aabb\nc cddee' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g' | 
> while read; do echo "${REPLY}x"; done
aabbx
c cdde ex
# no spaces added at the end of the first line (while loop to add to the end of
# the line and show this)
Fred Nurk
sumber
0

Saya telah melakukan ini dengan menggunakan python

Pertama saya membaca file kemudian saya membaginya dengan 4 karakter dan menambahkan ruang

#!/usr/bin/python
import re
b=re.compile(r'[a-z]{4}')

p=open('/root/l.txt','r')
i=p.readlines()
for j in i:
    m=re.findall(b,j)
print " " .join (m) + "  "

/root/l.txt ==> Terdiri dari konten yang Anda berikan dalam contoh

keluaran

foob arba zbla rgbl
Praveen Kumar BS
sumber