在`sed`中,如何在字符串中的字符之间放置一个“&”?


Answers:


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删除并重新添加行尾;在中设置的定界符(这里是一个空字符串)上输入split进行-a填充。结果是将每个字符均分为,然后将它们与“&”连接起来,然后打印该行。)@F-F@F

或者:

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

(替换每个字符,前提是每个字符前面都有另一个字符(后置正则表达式运算符(?<= ...))

使用zshshell运算符:

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

(再次,使用s::参数扩展标志在空字段分隔符上进行拆分,然后与结合&

要么:

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

&使用${var//pattern/replacement}ksh运算符替换每次出现的内容(因此在每个字符之前)(尽管在ksh空模式中表示其他内容,但是我不确定bash),然后使用POSIX ${var#pattern}剥离删除第一个运算符)。

使用ksh93shell运算符:

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

~(P:perl-like-RE)是一个ksh93 glob运算符,以使用类似perl的正则表达式(尽管与perl或PCRE的表达式不同),(?=.)是一个超前运算符:替换一个字符,前提是该字符后跟另一个自身(\0)和&

要么:

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

(将每个字符(?)替换为&和自身(\0),然后删除多余的字符)

使用bashshell运算符:

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

(与相同zsh,除了您需要@()在那里(需要extglob在其中输入ksh glob运算符bash))。


2
@AFSHIN,这不会对工作012345投入
斯特凡Chazelas

1
这应该工作awk -F '' -v OFS="&" 'NF=NF'
αғsнιη

1
@AFSHIN,但删除空行。更一般而言,将操作用作条件并打算打印操作结果时,需要确保操作返回的值不是空字符串或解析为0的数字字符串。
StéphaneChazelas

1
您能否简单说明一下它们的工作原理?看来这里有一些很棒的东西要学习,但是我什至不知道我将在哪里开始研究其中的大多数内容,以了解如何在特定问题的范围之外应用它们。
IMSoP

1
@StéphaneChazelas辉煌,谢谢。在复杂的文档中搜索诸如sed之类的东西有点技巧,因此拥有一些动手实例是学习以前从未见过的新知识的一种好方法。
IMSoP '17

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中的字符而不是TAB

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

(请注意,如果输入包含多行,它们将与连接在一起&


2
多字节字符失败。试试echo "abcdeéèfg" | fold -1 | paste -sd\& -
艾萨克(Isaac)

3
@Arrow很可能您只是在使用折叠越野车 coreutils版本,它没有完整的Unicode支持。BSD折叠,coreutils的 RedHat补丁版本(即Fedora或CentOS)以及它的BusyBox实现,都可以很好地处理Unicode。
Zeppelin

5
这个问题是关于sed
亚历山大

6
@Alexander-是的,sed下面有很多不错的答案。在演示如何用其他方法解决任务方面,我认为没有什么害处。
齐柏林飞艇

@StéphaneChazelas> POSIXly,您需要fold -w 1是的,我已经添加了"-w",谢谢! "-",则不需要 If no file operands are specified, the standard input shall be used
齐柏林飞艇


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!更新了答案。
亚历山大
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.