Her dört karakterden birinde uzun bir satıra nasıl boşluk eklerim?


30

Okumayı kolaylaştırmak için tek bir basit metin satırına, her 4 karakterde bir boşluk eklemek istediğim uzun bir satırım var, bunu yapmanın en kolay yolu nedir? ayrıca hattı bir borudan girebilmeliyim. Örneğin

echo "foobarbazblargblurg" | <some command here>

verir

foob arba zbla rgbl urg

Yanıtlar:


54

Sed'i aşağıdaki gibi kullanın:

$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg

1
Küfrederek o kadar yakındı lanetledimsed ilk önce kendimi tekmeleyebilirim.
xenoterracide

7
Merak ediyorum, '&' başarısı nedir? Oh, 'daha yeni eşleştiren şey' için durgun. Aptal ben.
Omnifarious

1
İstenmeyebilecek bir karakterden başka bir karakter varsa, bunun da sonuna bir boşluk eklediği unutulmamalıdır
Anubis

@Anubis's/.\{4\}/& /g;s/ $//'
wieczorek1990

20

Aşağıdaki basit örneği kullanabilirsiniz:

$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl

Çok hoş ... Bunun sedcevabından daha iyi olduğunu düşünüyorum . Daha foldönce bilmiyordum .
Wildcard,

1
Ne yazık ki, GNU’nun şu anki sürümlerinde, foldçoklu bayt karakterleriyle ( echo €€€€€€€€ | fold -w4 | paste -sd' ' -UTF-8’de olduğu gibi) çalışmaz .
Stéphane Chazelas

3

İşte grepve kullanarak örnek xargs:

$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl

xargsechovarsayılan olarak çalışır , bu nedenle uygulamaya -nenbağlı olarak ters eğik çizgi içeren veya benzeri kelimelerle çalışmaz echo. Garip newline karakterini arada sırada göreceksiniz, ayrıca xargs birden fazla çalışıyorsa echo. paste -sd ' ' -Bunun yerine boru için daha iyi . Bunun -ostandart bir seçenek olmadığını unutmayın .
Stéphane Chazelas

3

Sadece bash'da harici komut yok:

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

veya tek hatlı boru versiyonu:

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

Bunun işleyişi, dizgenin her karakterini regex eşleşmesi ve yakalama için bir "(.)" Biçimine dönüştürmek ve =~ardından BASH_REMATCH[]dizilimden yakalanan ifadeleri gerektiği gibi gruplandırmaktır. Lider / iz / ara alanlar korunur, "${BASH_REMATCH[@]:1}"atlamak için etrafındaki tırnak işaretlerini kaldırın .

Burada bir fonksiyona sarılır, bu herhangi bir argüman yoksa, argümanlarını işler veya stdin'i okur:

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 

Format dizesini uygun şekilde ayarlamak için sayımı kolayca parametreleyebilirsiniz.

Takip eden bir boşluk eklenirse, printfsorun olursa bir tane yerine iki saniye kullanın:

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

İlki ilk printf4 karakteri (en fazla) basar, ikincisi koşullu olarak tüm diğerlerini (varsa) grupları ayırmak için başlarında boşluk bırakarak yazdırır. Test, sıfırıncı elementi hesaba katması için 4 değil 5 element içindir.

Notlar:

  • Shell'in printf'ın %cyerine kullanılabilir %s, %c(belki) niyet net yapar, ancak multi-byte karakter güvenli değil. Bash sürümünüzün yetenekli olması durumunda, yukarıdakilerin hepsi çok baytlık karakter güvenlidir.
  • kabuk printf, biçim dizgisini argümanlar tükenene kadar yeniden kullanır, bu nedenle bir seferde 4 argüman toparlar ve izleyen argümanları ele alır (bu nedenle, tartışmasız yanlış olan diğer cevapların aksine, kenar davaları gerekmez)
  • BASH_REMATCH[0] tüm eşleşen dize, bu nedenle yalnızca dizin 1'den başlayan çıktı
  • kullanmak printf -v myvar ...bir değişkene mağazaya yerine myvar(her zamanki salt döngü / altkabuk davranışına bağlı)
  • printf "\n"gerekirse ekle

zshDiziyi kullanmak match[]yerine yukarıdakileri çalıştırabilir BASH_REMATCH[]ve tüm dizinde zshbir 0 öğesi tutmadığından tüm dizinlerden 1 çıkarabilirsiniz .


3

İle zshsadece:

str=foobarbazblargblurg

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

Veya

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

ile ksh93sadece:

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

Yalnızca herhangi bir POSIX kabuğuyla (giriş uzunluğu 4 katı ise, boşluktan kaçının):

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"

Şimdi, bu karakterler için . Eğer (örneğin kırmak için sesletim kümelerinden bunu yapmak istiyorsa Stéphane, olarak yazılır $'Ste\u0301phane'gibi Stép hanedeğil Ste phan ebirlikte,) zsh:

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

Ksh93 ile Stéphaneyukarıdakiler için de geçerli olan ekran genişliğini de kırabilir , ancak diğer bazı sıfır genişlikli veya çift genişlikli karakterlerin söz konusu olduğunda da yardımcı olabilir:

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"

2

Sadece gerektiği kadar boşluk ekleyerek cevaplayacağım, böylece bir satırda en az 4 karakterden sonra bir boşluk belirir; bu olayı hangi şekilde ele almak istediğinden emin değilim. Örneğin, "aa bbccdd" girişi verildiğinde, "aa b bccd d" yerine "aa bbcc dd" çıktısı alırsınız.

Perl'i bakmak için kullanıyorum, ama genel olarak Perl'i pek tanımadım, bu yüzden gerekli tweaks olabilir:

$ 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)

0

Bunu python kullanarak yaptım

Önce dosyayı okudum, sonra 4 karaktere böldüm ve boşluk ekliyorum

#!/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 ==> Örnekte verdiğiniz içerikten oluşur.

çıktı

foob arba zbla rgbl
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.