Як у "sed" я можу поставити одне "&" між символами в рядку?


Відповіді:


25

З GNU sed:

sed 's/./\&&/2g'

( sвставте кожен ( g) символ ( .) з тим самим ( &), який передує &( \&), але тільки починаючи з другого появи ( 2)).

Портативно:

sed 's/./\&&/g;s/&//'

(замінюйте кожну подію, але потім видаліть перше, &чого ми не хочемо).

З деякими awkреалізаціями (не POSIX, оскільки поведінка не визначено для порожнього FS):

awk -F '' -v OFS="&" '{$1=$1;print}'

gawkкількома іншими awkреалізаціями, порожній роздільник поля розділяє записи на його складові символи . Розділювач поля виводу ( OFS) встановлюється &. Присвоюємо значення $1(самому), щоб змусити регенерувати запис за допомогою нового роздільника поля. Перш ніж надрукувати його, він NF=NFтакож працює і є дещо ефективнішим у багатьох реалізаціях, але поведінка, коли ви це робите, наразі не визначена POSIX).

perl:

perl -F -lape '$_=join"&",@F' 

( -peзапускає код для кожного рядка та друкує результат ( $_); -lзнімає та повторно додає закінчення рядків автоматично; -aзаповнюється @Fрозділеним введенням на роздільнику -F, який є порожнім рядком. Результатом є розділення кожного символу на @F, потім приєднайте їх до "&" та надрукуйте рядок.)

Як варіант:

perl -pe 's/(?<=.)./&$&/g' 

(замініть кожен символ за умови, що йому передує інший символ (оглядовий оператор regexp (? <= =))

Використання zshоператорів оболонки:

in=12345
out=${(j:&:)${(s::)in}}

(знову ж таки, розділіть на порожній роздільник поля, використовуючи s::прапор розширення параметра, і з'єднайтеся з &)

Або:

out=${in///&} out=${out#?}

(замініть кожне виникнення нічого (тому перед кожним символом) за &допомогою ${var//pattern/replacement}оператора ksh (хоча в kshпорожньому шаблоні означає щось інше, а ще щось інше, я не впевнений, що в bash), і видаліть перше з ${var#pattern}позбавленням POSIX оператор).

Використання ksh93операторів оболонки:

in=12345
out=${in//~(P:.(?=.))/\0&}

( ~(P:perl-like-RE)будучи глобальним оператором ksh93, щоб використовувати регулярні вирази, подібні до perl (відмінні від perl чи PCRE), (?=.)будучи оператором "заздалегідь": замініть символ за умови, що за ним слідує інший символ на себе ( \0) та &)

Або:

out=${in//?/&\0}; out=${out#?}

(замінюємо кожен символ ( ?) на &і себе ( \0), а ми видаляємо неперевершений)

Використання bashоператорів оболонки:

shopt -s extglob
in=12345
out=${in//@()/&}; out=${out#?}

( Такий же , як zsh«s, за винятком того, що вам потрібно @()є (а КШ Глоб оператор , для якого вам потрібно extglobв bash)).


2
@AFSHIN, це не працює на 012345вході
Stéphane Chazelas

1
це має спрацюватиawk -F '' -v OFS="&" 'NF=NF'
αғsnιη

1
@AFSHIN, але видаліть порожні рядки. Більш загально, використовуючи дію як умову та маючи намір друкувати результат дії, потрібно переконатися, що значення, повернене дією, не є порожнім рядком або числовим рядком, який дорівнює 0.
Stéphane Chazelas

1
Чи можете ви додати коротке пояснення того, як працює кожен із цих? Схоже, тут слід дізнатися деякі дивовижні речі, але я навіть не знаю, з чого я би почав досліджувати більшість з них, щоб побачити, як застосувати їх поза межами цієї конкретної проблеми.
IMSoP

1
@ StéphaneChazelas Блискуче, дякую. Пошук складних документів для таких речей, як sed, - трохи мистецтво, тому наявність практичних прикладів - це чудовий спосіб вивчення нових біт, яких ви ще не бачили.
IMSoP

15

Утиліти Unix:

fold -w1|paste -sd\& -

Пояснили:

"fold -w1" - прив’яже кожен символ введення до власного рядка

скласти - обернути кожен рядок вводу відповідно до заданої ширини

-w, --width = WIDTH використовувати WIDTH стовпці замість 80

%echo 12345|fold -w1
1
2
3
4
5

"paste -sd\& -"- об'єднає вхідні рядки разом, використовуючи &як роздільник

вставити - об'єднати рядки файлів

-s, - послідовна вставка одного файла за раз, а не паралельно

-d, --delimiters = СПИСОК повторного використання символів зі списку замість TAB

%fold -w1|paste -sd\& -
1&2&3&4&5

(Зверніть увагу, що якщо вхід містить кілька рядків, вони будуть об'єднані &)


2
Збій на багатобайтових символах. Спробуйтеecho "abcdeéèfg" | fold -1 | paste -sd\& -
Ісаак

3
@Arrow Швидше за все , ви просто використовуєте баггі Coreutils версію складка , яка не має повну підтримку Unicode. BSD-складка, RedHat-патч-версії coreutils (тобто Fedora чи CentOS), а також реалізація BusyBox, можуть добре працювати з Unicode.
zeppelin

5
Питання конкретно про sed.
Олександр

6
@Alexander - це правда, і нижче є ряд хороших sedвідповідей. І я не бачу ніякої шкоди в демонстрації того, як завдання можна вирішити іншими способами.
zeppelin

@ StéphaneChazelas> POSIX, вам знадобиться складання -w 1 Правда, я додав "-w", thx! "-", у свою чергу, не потрібно If no file operands are specified, the standard input shall be used
zeppelin


9
sed 's/\B/\&/g'

\ B - відповідність скрізь, але на межі слова; тобто це збігається, якщо символ зліва та символ праворуч є або символами «слова», або обома символами «не слова».

Інформація: посібник GNU sed, регулярні розширення виразів .

Тестування:

sed 's/\B/\&/g' <<< '12345'
1&2&3&4&5

5
Цікава ідея, але питання не говорить про те, що рядок не містить пробілу, крапки чи нічого, що могло б бути межею слова. Він просто говорить "між символами", який слід інтерпретувати як "будь-які символи".
xhienne

4

Це буде трохи повільніше, ніж деякі відповіді, але це цілком зрозуміло:

echo 12345 | perl -lnE 'say join "&", split //'

4

Ось ще один спосіб. Перша частина виразу sed фіксує кожного символу, а потім замінює його символом та символом. Друга частина видаляє амперсанд від кінця рядка.

echo 12345 | sed -r 's/(.)/\1\&/g;s/\&$//g'
1&2&3&4&5

Працює і на багатобайтових символах.


1
Не потрібно дзвонити sedдвічі, sedсценарій може мати кілька команд:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne

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