В `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также работает и немного более эффективен во многих реализациях awk, но поведение, когда вы делаете это, в настоящее время не определено POSIX).

perl:

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

( -peзапускает код для каждой строки и печатает результат ( $_); -lавтоматически удаляет и повторно добавляет окончания строк; -aзаполняется @Fвходным разделением по заданному разделителю -F, который здесь представляет собой пустую строку. В результате каждый символ разделяется на @F, затем соедините их с '&' и напечатайте строку.)

В качестве альтернативы:

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

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

Использование zshоператоров оболочки:

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

(снова разделить на пустой разделитель полей, используя s::флаг расширения параметра, и соединиться с &)

Или:

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

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

Использование 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входе
Стефан
1
это должно работатьawk -F '' -v OFS="&" 'NF=NF'
αғsнιη
1
@AFSHIN, но удалите пустые строки. В более общем случае, при использовании действия в качестве условия и намерении вывести результат действия, вы должны убедиться, что значение, возвращаемое действием, не является пустой строкой или числовой строкой, которая разрешается до 0.
Стефан Шазелас
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, --serial вставлять один файл за раз вместо параллельного

-d, --delimiters = LIST повторно использовать символы из LIST вместо вкладок

%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 просто замечательно.
Цеппелин
5
Вопрос конкретно о sed.
Александр
6
@ Александр - это правда, и есть несколько хороших sedответов, доступных ниже. И я не вижу никакого вреда в демонстрации того, как эта задача может быть решена другими средствами.
Цеппелин
@ StéphaneChazelas> POSIXly, вам нужно сложить -w 1 Правда, я добавил "-w", спасибо! "-", В свою очередь, не требуется If no file operands are specified, the standard input shall be used
дирижабль
11

использование sed

sed 's/./&\&/g;s/.$//'
αғsнιη
источник
9
sed 's/\B/\&/g'

\ B - Соответствует везде, но на границе слова; то есть совпадает, если символ слева и символ справа являются либо символами «слова», либо символами «не слова».

Информация: руководство по GNU sed, расширения регулярных выражений .

Тестирование:

sed 's/\B/\&/g' <<< '12345'
1&2&3&4&5
MiniMax
источник
5
Интересная идея, но вопрос не говорит о том, что строка не содержит пробела, точки или чего-либо, что могло бы составить границу слова. Он просто говорит «между символами», что следует понимать как «любые символы».
Ксиэнн
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
Ксиенн, спасибо, ТИЛ! Обновил ответ.
Александр