web-dev-qa-db-ja.com

各行の終わりにある空白の各文字を「_」で置き換えます

各行末の空白の各文字を「_」に置き換えたいのですが。空白文字をリードするための同様の質問と回答を見つけました。しかし、末尾の空白のためにそれを再構築することに失敗しました。これがリンクです: https://stackoverflow.com/questions/9222281/replace-leading-whitespace-with-sed-or-similar

誰かがより速くまたはより良い方法を考えることができれば、それも素晴らしいでしょう。私はまた、より早く学ぶことができるので、良い説明にも感謝します:)

Input:
foo bar
 foo bar oof
  line 3a  
  line fo a

Output:
foo bar_____
 foo bar oof
  line 3a___
  line fo a_
6
Giles

GNU awkの3番目の引数がmatch()およびgensub()の場合):

$ awk 'match($0,/(.*[^ ])(.*)/,a){$0=a[1] gensub(/ /,"_","g",a[2])} 1' file
foo bar_____
 foo bar oof
  line 3a___
  line fo a_

どのawkでも:

$ awk 'match($0,/ +$/){tail=substr($0,RSTART,RLENGTH); gsub(/ /,"_",tail); $0=substr($0,1,RSTART-1) tail} 1' file
foo bar_____
 foo bar oof
  line 3a___
  line fo a_

上記のgawkソリューションを調整して、先行ブランクも置き換えるには:

$ awk 'match($0,/^( *)(.*[^ ])(.*)/,a){$0=gensub(/ /,"_","g",a[1]) a[2] gensub(/ /,"_","g",a[3])} 1' file
foo bar_____
_foo bar oof
__line 3a___
__line fo a_
3
Ed Morton

GNU sedで、eolのすべてのスペースをアンダースコアに置き換えます:

sed ':x;s/ \( *\)$/_\1/;tx'  
9
Gerard H. Pille

Perlを使用する方が効率的です。

Perl -lpe 's/(\s+)$/"_" x length($1)/e' input.txt

これは、ループする代わりに、行ごとに1つの置換を行うだけで、末尾に空白を挿入する必要があります。

4
Shawn

Awkで

awk -F '[ \t]+$' 'NF>1{t=substr($0,length($1)+1);gsub(/./,"_",t); $0=$1 t} 1'

これはtrailingタブとスペースの混合も扱います。フィールド区切り文字(-FFS)は、スペースにのみ一致するように、または$で末尾にアンカーされたままであれば、他の種類の非表示文字にも一致するように簡単に調整できます。

これをleading空白で機能させるには、$から^だけでなく、すべてをミラーリングする必要があります。

awk -F '^[ \t]+' 'NF>1{h=substr($0,1,length()-length($2));gsub(/./,"_",h); $0=h $2} 1'

先頭と末尾の両方ブランクで機能させるには、ロジックを逆にする必要があります。フィールド区切り文字を、先頭と末尾の空白に一致するパターンにしないに設定します。

awk -F '[^ \t](.*[^ \t]|$)' '{s=$0; h=gsub(/./,"_",$1); t=gsub(/./,"_",$2); print $1 substr(s,h+1, length(s)-h-t) $2}'

または調整可能なパターンで同じ:

awk -v ns='[^ \t]' 'BEGIN{FS=ns"(.*"ns"|$)"}{s=$0; h=gsub(/./,"_",$1); t=gsub(/./,"_",$2); print $1 substr(s,h+1, length(s)-h-t) $2}'

@ EdMortonのソリューション とは異なり、これらはスペースのみを含む行を正しく処理し、GNU awk(gawk)だけでなく、awkの任意の実装で機能します。例: mawkまたはbwk( "original-awk")はどちらもgawkよりもはるかに高速ですが、gawkを使用した場合でも、最後のソリューションは@EdMortonのほぼ2倍の速度になります。

セッド付き

Sedで私が考えることができる唯一の解決策は、ループで繰り返し置換することです。末尾のスペースと長い行が多い場合、これは遅くなる可能性があります:

sed -e :x -e 's/ \( *\)$/_\1/;tx'

sed ':x;s/ \( *\)$/_\1/;tx'standard sedではないことに注意してください。 :labelは、;で終了できるコマンドの1つではありません。

編集コマンド以外{...}abcirtw:、および#の後には、<semicolon>、オプションの<blank>文字、および別の編集コマンドを続けることができます。

Perlを使用

これは、既存の Perlの回答 を実際に改善したものではない代替のPerlソリューションですが、s///eフラグを使用しないため、理論的には変更できます正規表現でsedのようなs///およびPerl/pcreのようなゼロ幅アサーションを提供する他のいくつかのツールに:

Perl -ple 's/\s(?=\s*$)/_/g'
2
mosvy

次の簡単な方法でもこれを行うことができます:

Perlは空白以外で分割し、最後のフィールドでアンダースコアを付けるためにスペースの文字変換を実行します。次に、すべてのフィールドを印刷します。

$ Perl -F'(\S+)'  -lane '
    $F[-1] =~ tr/ /_/ if @F;
    print @F;
' file 

GNU sedを使用して、先読みと同等の処理を実行します。

$ sed -re '
    y/ /\n/
    :loop
      s/\n(\S| )/ \1/
    tloop
    y/\n/_/
' file 

これは正反対に機能します(\ Sを[^ [:space:]]に変更します)

$ sed -e '
    h;s/\s*$//;x;s/.*\S//
    y/ /_/;x;G;s/\n//
' file 

このメソッドはs /// e拡張フラグを利用するため、gnu sedでのみ機能します。

$ sed -re '
    s/(.*\S)(.*)/echo "\1""$(echo "\2" | tr " " _)"/e
' file 
0
Rakesh Sharma

行を均等にするためにadd whitespaceをしようとしている場合:

$ cat -A file
foo bar$
 foo bar oof$
  line 3a  $
  line fo a$

線は均一ではありません

Perl -MList::Util=max -lne '
    Push @lines, $_
}
END {
    $wid = max map {length} @lines;
    for $line (@lines) {
        $padded = sprintf "%-*s", $wid, $line;
        $padded =~ s/(\s+)$/"_" x length($1)/e;
        print $padded
    }
' file
foo bar_____
 foo bar oof
  line 3a___
  line fo a_
0
glenn jackman