web-dev-qa-db-fra.com

Comment insérer un espace tous les quatre caractères dans une longue ligne?

J'ai une longue ligne que je veux insérer un espace tous les 4 caractères, sur une seule ligne isolée de texte solide pour faciliter la lecture, quel est le moyen le plus simple de le faire? De plus, je devrais pouvoir saisir la ligne d'un tuyau. par exemple.

echo "foobarbazblargblurg" | <some command here>

donne

foob arba zbla rgbl urg
34
xenoterracide

Utilisez SED comme suit:

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

Vous pouvez utiliser l'exemple simple suivant:

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

Avec zsh uniquement:

str=foobarbazblargblurg

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

Ou

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

avec ksh93 seul:

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

Avec n'importe quelle coquille POSIX uniquement (évitant également l'espace de fin si la longueur d'entrée est un multiple de 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"

Maintenant, c'est pour caractères. Si vous vouliez le faire sur des grappes graphèmes (par exemple, briser Stéphane, écrit comme $'Ste\u0301phane', comme Stép hane et pas Ste phan e), avec zsh:

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

Avec KSH93, vous pourriez également casser la largeur d'affichage, ce qui fonctionnerait pour ça Stéphane ci-dessus, mais pourrait également aider lorsque d'autres types de caractères zéro-largeur ou de double largeur sont impliqués:

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"
4
Stéphane Chazelas

En bash seulement, pas de commandes externes:

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

ou en tant que version de tuyau d'une ligne:

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

La façon dont cela fonctionne est de convertir chaque caractère de la chaîne à un " (.) " Pour une comparaison regex et capture avec =~, Alors que la sortie des expressions capturées à partir BASH_REMATCH[] Tableau, regroupées selon les besoins. Leading/arrière/espaces intermédiaires sont conservés, enlever les guillemets autour "${BASH_REMATCH[@]:1}" De les omettre.

Ici, il est enveloppé dans une fonction, celle-ci traitera ses arguments ou lire stdin s'il n'y a pas d'arguments:

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 

Vous pouvez facilement paramétrer le compte pour ajuster la chaîne de format en conséquence.

Un espace arrière est ajouté, l'utilisation de deux printf s au lieu d'un, si c'est un problème:

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

Les premiers printf tirages (jusqu'à) les 4 premiers caractères, la deuxième condition imprime tout le reste (le cas échéant) avec un espace qui conduit à séparer les groupes. Le test est de 5 éléments non 4 pour tenir compte de l'élément zeroth.

Remarques:

  • Shell printf 'S%c Pourrait être utilisé au lieu de %s, %c (Peut-être) rend l'objet plus claire, mais pas de caractères multi-octets. Si votre version de bash est capable, ce qui précède est tout caractère multi-octets.
  • Shell printf réutilise sa chaîne de format jusqu'à ce qu'il court d'arguments, donc juste gobe 4 arguments à la fois, et gère les arguments de suivi (si aucun cas Edge nécessaire, contrairement à certains des autres réponses ici qui sont sans doute tort)
  • BASH_REMATCH[0] Est l'ensemble de la chaîne correspondante, de sorte que la sortie de départ à partir de l'index 1
  • utilisation printf -v myvar ... Au lieu de stocker à une variable myvar (sous réserve de lecture en boucle habituelle/comportement sous-shell)
  • ajouter printf "\n" si nécessaire

Vous pouvez faire le travail ci-dessus dans zsh si vous utilisez le tableau match[] à la place de BASH_REMATCH[], Et soustraire 1 de tous les indices que zsh ne garde pas un élément 0 avec le match.

3
mr.spuratic

Voici l'exemple en utilisant grep et xargs:

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

Je l'ai fait en utilisant python

D'abord, je lis le fichier alors je divise de 4 personnages et ajoute de l'espace

#!/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 ==> se compose du contenu que vous avez donné par exemple

sortir

foob arba zbla rgbl
0
Praveen Kumar BS