Come inserisco uno spazio ogni quattro caratteri in una riga lunga?


30

Ho una lunga riga che voglio inserire uno spazio ogni 4 caratteri, su una singola riga di testo solido per rendere più facile la lettura, qual è il modo più semplice per farlo? inoltre dovrei essere in grado di inserire la linea da una pipe. per esempio

echo "foobarbazblargblurg" | <some command here>

foob arba zbla rgbl urg

Risposte:


54

Usa sed come segue:

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

1
imprecando che era così vicino al sedprimo tentativo che ho potuto calciare.
xenoterracide,

7
Solo curioso, qual è il '&' realizzare? Oh, rappresenta una "cosa che si è appena abbinata". Sciocco me
Onnipotente il

1
va notato che questo aggiunge uno spazio anche alla fine se c'è un altro carattere nella stringa, che potrebbe non essere desiderabile
Anubi

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

21

È possibile utilizzare il seguente semplice esempio:

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

Molto bello ... Penso che sia persino meglio della sedrisposta. Non lo sapevo foldprima.
Carattere jolly

1
Sfortunatamente, con le versioni attuali di GNU fold, non funziona con caratteri multi-byte (come echo €€€€€€€€ | fold -w4 | paste -sd' ' -in UTF-8).
Stéphane Chazelas,

3

Ecco l'esempio usando grepe xargs:

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

xargsviene eseguito echoper impostazione predefinita, quindi non funzionerà con parole come -neno che contengono barre rovesciate a seconda echodell'implementazione. Di tanto in tanto vedrai lo strano carattere di nuova riga se xargs ne esegue più di uno echo. Meglio pipare paste -sd ' ' -invece. Nota che -onon è un'opzione standard.
Stéphane Chazelas,

3

Solo in bash, nessun comando esterno:

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

o come versione a tubo a una riga:

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

Il modo in cui funziona è convertire ogni carattere della stringa in "(.)" Per far corrispondere e catturare regex =~, quindi emettere le espressioni catturate BASH_REMATCH[]dall'array, raggruppate come richiesto. Gli spazi iniziali / finali / intermedi vengono conservati, rimuovere le virgolette intorno "${BASH_REMATCH[@]:1}"per ometterle.

Qui è racchiuso in una funzione, questo elaborerà i suoi argomenti o leggerà stdin se non ci sono argomenti:

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 

È possibile parametrizzare facilmente il conteggio per adattare di conseguenza la stringa di formato.

Viene aggiunto uno spazio finale, utilizzare due printfs anziché uno se questo è un problema:

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

Il primo printfstampa (fino a) i primi 4 caratteri, il secondo stampa condizionatamente tutto il resto (se presente) con uno spazio iniziale per separare i gruppi. Il test è per 5 elementi non 4 per tenere conto dell'elemento zeroth.

Gli appunti:

  • shell printfs' %cpotrebbero essere usati al posto di %s, %c(forse) libera l'intento chiaro, ma non è multi-byte sicuro carattere. Se la tua versione di bash è in grado, quanto sopra è sicuro per tutti i caratteri multi-byte.
  • shell printfriutilizza la sua stringa di formato fino a quando non esaurisce gli argomenti, quindi divora solo 4 argomenti alla volta e gestisce gli argomenti finali (quindi non sono necessari casi limite, a differenza di alcune delle altre risposte qui che sono probabilmente sbagliate)
  • BASH_REMATCH[0] è l'intera stringa corrispondente, quindi solo output a partire dall'indice 1
  • utilizzare printf -v myvar ...invece per archiviare in una variabile myvar(soggetto al solito comportamento di ciclo di lettura / subshell)
  • aggiungere printf "\n"se necessario

È possibile far funzionare quanto sopra zshse si utilizza l'array match[]anziché BASH_REMATCH[]e sottrarre 1 da tutti gli indici poiché zshnon mantiene un elemento 0 con l'intera corrispondenza.


3

zshSolo con :

str=foobarbazblargblurg

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

O

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

con ksh93solo:

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

Solo con qualsiasi shell POSIX (evitando anche lo spazio finale se la lunghezza di input è un multiplo di 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"

Questo è per i personaggi . Se volevi farlo sui grappoli (ad esempio, rompere Stéphane, scritto come $'Ste\u0301phane', come Stép hanee non Ste phan e), con zsh:

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

Con ksh93, potresti interrompere anche la larghezza di visualizzazione, il che funzionerebbe per quello Stéphanesopra, ma potrebbe anche aiutare quando sono coinvolti altri tipi di caratteri di larghezza zero o doppia larghezza:

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

Risponderò inserendo solo gli spazi richiesti, in modo che uno spazio appaia almeno dopo ogni 4 caratteri su una riga; non so in che modo vuoi gestire questo caso. Ad esempio, dato l'input di "aa bbccdd", otterrai l'output "aa bbcc dd" anziché "aa bccd d".

Sto usando Perl per lookahead, ma non ho molta familiarità con Perl in generale, quindi potrebbero esserci delle modifiche necessarie:

$ 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

L'ho fatto usando Python

In primo luogo sto leggendo il file, quindi sto dividendo per 4 caratteri e aggiungendo spazio

#!/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 ==> È costituito dal contenuto che hai fornito nell'esempio

produzione

foob arba zbla rgbl
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.