`sed`では、文字列の文字間に「&」を1つ挿入するにはどうすればよいですか?


11

sed次のようなものを作ることができます:

12345

になる:

1&2&3&4&5

回答:


25

GNUの場合sed

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

substitute毎(g)文字(.)と同じと(&)で始まる&\&)だけ第二の発生(から始まります2))。

ポータブル:

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

(すべての出現箇所を置き換えますが、不要なものを最初に削除し&ます)。

一部のawk実装では(動作は空のFSに対して指定されていないため、POSIXではありません):

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#?}

(何もないすべての文字の前に)ksh演算子を&使用して置換します(空のパターンは他の何かを意味しますが、何か他のものを意味しますが、私はの内容がわかりません)、最初のものをPOSIX ストリッピングで削除しますオペレーター)。${var//pattern/replacement}kshbash${var#pattern}

ksh93シェル演算子を使用する:

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

~(P:perl-like-RE)perlのような正規表現を使用するksh93 glob演算子(perlやPCREとは異なります)、(?=.)先読み演算子:文字の後に別の文字が続く場合はそれ自体を置き換えます(\0)および&

または:

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

(すべての文字(?)を&and自体(\0)に置き換え、スーパーフロースの文字を削除します)

bashシェル演算子を使用する:

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

(同じzshあなたが必要とすることを除いて、の@()が(あなたが必要があるためkshのグロブ演算子extglobbash))。


2
上で動作しないでしょう@AFSHIN、012345入力
ステファンChazelas

1
これは動作するはずですawk -F '' -v OFS="&" 'NF=NF'
αғsнιη

1
@AFSHIN、ただし空行を削除します。より一般的には、アクションを条件として使用し、アクションの結果を出力する場合は、アクションによって返される値が空の文字列または0に解決される数値文字列でないことを確認する必要があります。
StéphaneChazelas

1
これらのそれぞれがどのように機能するかについて簡単な説明を追加できますか?ここで学ぶべき素晴らしいことがいくつかあるように見えますが、この特定の問題の範囲外でそれらを適用する方法を見るためにそれらのほとんどをどこから研究し始めるのかさえ知りません。
IMSoP 2017

1
@StéphaneChazelasブリリアント、ありがとう。sedのようなものを複雑なドキュメントで検索するのはちょっとした芸術です。そのため、いくつかの実践的な例を持っておけば、これまで見たことのない新しい部分を学ぶことができます。
IMSoP 2017

15

Unixユーティリティ:

fold -w1|paste -sd\& -

説明:

"fold -w1" -各入力文字を独自の行にラップします

fold-指定された幅に収まるように各入力行を折り返します

-w、-width = WIDTHは、80ではなくWIDTH列を使用します

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

"paste -sd\& -"- &セパレータとして使用して、入力行をマージします

貼り付け-ファイルの行をマージ

-s、--serial並列ではなく一度に1つのファイルを貼り付け

-d、--delimiters = LIST TABの代わりにLISTの文字を再利用します

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

(入力に複数の行が含まれている場合、それらはで結合されます&


2
マルチバイト文字で失敗します。試してみるecho "abcdeéèfg" | fold -1 | paste -sd\& -
アイザック

3
@Arrowおそらく、バグのある coreutilsバージョンのfoldを使用しているだけで、完全なUnicodeサポートはありません。BSDフォールド、coreutils(つまりFedoraまたはCentOS)のRedHatパッチバージョン、およびそのBusyBox実装は、Unicodeを適切に処理できます。
ツェッペリン

5
質問は特にですsed
アレクサンダー

6
@アレクサンダー-それは真実であり、sed以下に利用可能な多くの良い答えがあります。また、他の方法でタスクを解決する方法を説明しても害はありません。
zeppelin 2017

@StéphaneChazelas> POSIXly、fold -w 1 trueが必要です。Trueを追加しました"-w""-"必要 ありませIf no file operands are specified, the standard input shall be used
zeppelin 2017


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式の最初の部分はすべての文字をキャプチャし、それを文字とアンパサンドに置き換えます。2番目の部分は、行の終わりからアンパサンドを削除します。

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

マルチバイト文字でも機能します。


1
sed2回呼び出す必要はありません。sedスクリプトにはいくつかのコマンドがありますsed -r 's/(.)/\1\&/g; s/\&$//g'
。– xhienne

xhienne、ありがとう、TIL!答えを更新しました。
アレクサンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.