Як вставити пробіл кожні чотири символи у довгий рядок?


30

У мене довгий рядок, що я хочу вставляти пробіл кожні 4 символи, в одному самотньому рядку суцільного тексту, щоб полегшити читання, який найпростіший спосіб це зробити? також я повинен мати можливість вводити лінію з труби. напр

echo "foobarbazblargblurg" | <some command here>

дає

foob arba zbla rgbl urg

Відповіді:


54

Використовуйте sed таким чином:

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

1
проклинаючи, що було так близько до того, що sedя спробував спочатку, я міг бити себе ногами.
ксенотерацид

7
Просто цікаво, що досягає "і"? О, це позиція для "тієї речі, яка щойно збігалася". Дурний мене.
всезначний

1
слід зауважити, що це додає пробіл наприкінці, якщо в рядку є ще один символ, який, можливо, не буде бажаним
Анубіс,

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

21

Можна використовувати наступний простий приклад:

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

Дуже приємно ... Я думаю, це навіть краще, ніж sedвідповідь. Я про це foldраніше не знав .
Wildcard

1
На жаль, у поточних версіях GNU foldвін не працює з багатобайтовими символами (як echo €€€€€€€€ | fold -w4 | paste -sd' ' -у UTF-8).
Стефан Шазелас

3

Ось приклад використання grepта xargs:

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

xargsпрацює echoза замовчуванням, тому він не працюватиме з такими словами, -nenякі містять зворону косу рису, залежно від echoреалізації. Ви побачите дивний символ нового рядка час від часу також, якщо xargs виконує більше одного echo. Краще paste -sd ' ' -замість труби . Зверніть увагу, що -oце не стандартний варіант.
Стефан Шазелас

3

Лише в bash, немає зовнішніх команд:

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

або як однолінійний варіант труби:

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

Як це працює, це перетворити кожен символ рядка в "(.)" Для збігу регулярних виразів і захоплення за допомогою =~ виразів , а потім просто вивести захоплені вирази з BASH_REMATCH[]масиву, згрупувавши за необхідністю. Провідні / кінцеві / проміжні пробіли зберігаються, видаліть лапки навколо, "${BASH_REMATCH[@]:1}"щоб їх опустити.

Тут він завершений у функцію, він обробляє свої аргументи чи читатиме stdin, якщо немає аргументів:

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 

Ви можете легко параметризувати кількість, щоб відповідно відрегулювати рядок формату.

Додано проміжний простір, використовуйте два printfs замість одного, якщо це проблема:

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

Перший printf друкує (до) перші 4 символи, другий умовно друкує всі інші (якщо такі є) провідним пробілом для розділення груп. Тест призначений для 5 елементів, а не 4 для обліку нульового елемента.

Примітки:

  • shell printf's %cможе бути використаний замість %s, %c(можливо) робить наміри яснішими, але це не багатобайтовий символ. Якщо ваша версія bash здатна, перераховане вище для всіх багатобайтових символів.
  • оболонки printf повторно використовує рядок формату, поки у неї не вистачає аргументів, тому вона просто збиває 4 аргументи за один раз і обробляє зворотні аргументи (тому не потрібні крайові випадки, на відміну від деяких інших відповідей тут, які, мабуть, неправильні)
  • BASH_REMATCH[0] - це весь збігований рядок, тому тільки вихід, починаючи з індексу 1
  • використовувати printf -v myvar ...замість цього для зберігання змінноїmyvar (залежно від звичайної поведінки читання циклу / підрозділу)
  • додати, printf "\n"якщо потрібно

Ви можете зробити вищезгадану роботу в тому zshвипадку, якщо ви використовуєте масив match[]замість BASH_REMATCH[], і віднімете 1 з усіх індексів, так як zshне зберігається 0 елемент за весь збіг.


3

З zshтільки:

str=foobarbazblargblurg

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

Або

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

з ksh93тільки:

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

Тільки з будь-якою оболонкою POSIX (також уникаючи місця проміжку, якщо довжина вводу кратна 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"

Тепер це для персонажів . Якщо ви хотіли це зробити на кластерних графемах (наприклад, перервати Stéphane, записані як $'Ste\u0301phane', як Stép haneі ні Ste phan e), за допомогою 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 ви можете також розбиватись на ширину дисплея, що може працювати для цього Stéphaneвище, але також може допомогти, якщо задіяні інші види символів нульової ширини або подвійної ширини:

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

Я відповім, лише вставляючи пробіли, як потрібно, щоб пробіл з’являвся принаймні після кожні 4 символи рядка; не впевнений, в який спосіб ви хочете розглянути цю справу. Наприклад, з урахуванням "aa bbccdd", ви отримаєте вихід "aa bbcc dd", а не "aa b bccd d".

Я використовую Perl для пошуку, але я взагалі не дуже знайомий з Perl, тому можуть бути потрібні налаштування:

$ 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

Я зробив це за допомогою python

Спочатку я читаю файл, потім я ділюсь на 4 символи та додаю пробіл

#!/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 ==> Складається із вмісту, який ви вказали у прикладі

вихід

foob arba zbla rgbl
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.