行の先頭のスペースを「-」に置き換えます。

行の先頭のスペースを「-」に置き換えます。
 wqdq
 wqdqgrhehr
 cnkzjncicoajc
 hello space
    oejwfoiwejfow
    wqodojw
    more spaces
    more

これは次の内容にしたいファイルですsed

-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

これを達成するにはループを使用する必要がありますか、それとも別の方法がありますか?私はこれを試しました:

user:~$ sed -n  '
: loop
  s/^ /-/
  s/[^-] /-/p
t loop' spaces

答え1

の場合、sed次のようなループが必要です。

sed -e :1 -e 's/^\( *\) /\1-/; t1' < file

または、次のようにします。

sed '
s/ */&\
/; # add a newline after the leading spaces
h; # save a copy on the hold space
y/ /-/; # replace *every* space with -
G; # append our saved copy
s/\n.*\n//; # remove the superflous part' < file

を使用すると、perl次のことができます。

perl -pe 's{^ *}{$& =~ y/ /-/r}e' < file

または

perl -pe 's/(^|\G) /-/g' < file

\GPCRE一致(幅なし)から前の一致の終わり(//gコンテキスト内)。したがって、ここでは、^行の先頭または前の一致の最後に続くスペース(つまり、以前に置き換えられたスペース)を置き換えます。

(この方法はsedPCREをサポートする実装で使用することもできますssed -R。)

を使用すると、awk次のことができます。

awk '
  match($0, /^ +/) {
    space = substr($0, 1, RLENGTH)
    gsub(" ", "-", space)
    $0 = space substr($0, RLENGTH+1)
  }
  {print}' < file

<space><tab>fooタブ文字を(例:に)変換したい場合は、前処理され--------fooた入力を使用できますexpand。 GNUを使用すると、行の先頭のスペースにあるタブ文字のみを変換expandできます。expand -iこのオプションを使用して、タップ停止間の距離を指定できます(デフォルトは8列ごと)-t

これを水平間隔のすべての文字、または少なくとも[:blank:]ロケールカテゴリに属する​​文字に一般化することはより複雑になります。

これはTAB文字がない場合にのみ問題になります。

perl -Mopen=locale -MText::CharWidth=mbswidth -pe 's/^\h+/"-" x mbswidth($&)/e'

しかし、TAB文字はコントロール文字の幅はですが、-1実際にmbswidth()持つ幅は行内の位置に応じて1列から8列まで異なります。

このexpandコマンドはそれを次に拡張します。正しいただしexpand、マルチバイト文字がある場合(UTF-8ロケールのタブとスペースを除くすべての空白文字)、GNUを含む多くの実装はこれを正しく処理しないため、マルチバイト文字をサポートする一部の実装でも幅0または幅2つの個人文字([:blank:]少なくとも一般的なGNUロケールではU + 3000など)である。したがって、TAB拡張は次のように手動で実行する必要があります。

perl -Mopen=locale -MText::CharWidth=mbswidth -pe 's{^\h+}{
  $s = $&;
  while ($s =~ /(.*?)\t(.*)/) {
    $s = $1 . (" " x ((7-mbswidth($1)) % 8 + 1)) . $2;
  }
  "-" x mbswidth($s)}e'

答え2

Stephaneが正しいsed解決策を提供しました。以下は、小さくて明確なPython 3の選択肢です。

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as f:
    for line in f:
        beginning = True
        for char in line:
            if beginning and char == " ":
                print("-",end="")
            else:
               beginning = False
               print(char,end="")

テスト実行:

# This is the input text
$ cat -A input.txt
 wqdq$
 wqdqgrhehr$
 cnkzjncicoajc$
 hello space$
    oejwfoiwejfow$
    wqodojw$
    more spaces$
    more$
    $
 $
  $

# And this is the output with the given python script
$ ./add_dashes.py ./input.txt                                                                                            
-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

答え3

別のawk方法:

awk 'match($0, /^[[:space:]]+/){ p=""; l=RLENGTH; while(l--) p=p"-";
     sub(/^[[:space:]]+/,p); print}' yourfile

出力:

-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

match($0, /^[[:space:]]+/)- 先行スペースがあるシーケンスと一致します。

l=RLENGTH- ラインごとに一致するシーケンスのサイズ

while(l--) p=p"-"- 代替サブストリングの構成



選ぶPython3.x 方法:

ハイフン.pyの空白スクリプト:

import sys, re
with open(sys.argv[1], 'r') as f:  # reading input file
    for l in f.read().splitlines():
        m = re.match(r'^ +', l)    # capture sequence of leading spaces 
        print(l if not m else l.replace(' ', '-', m.end()))

使用法:

python3 space_to_hyphen.py yourfile

答え4

布材

ループを設定し、行do-whileにまだ先行スペースがある間は、スペースではなく最初のスペースに隣接する最後のスペースを変換し続けます。

sed -e '
   :loop
      /^ /s/ \([^ ]\|$\)/-\1/
   tloop
' filename.ext


while IFS= read -r l; do
   read -r ll <<<"$(printf '%ss\n' "$l")"
   printf '%s%s\n' \
      "$(seq -s= 0 "$(expr "$l" : '[   ]*')" | tr = - | tr -cd -)" \
      "${ll%?}"
done < filename.ext

結果

-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

動作原理

  • whileファイルを1行ずつ読み込むようにループを設定し、に設定しIFSますNULL。これの目的は、行のすべてのスペースを維持することです。
  • 次に、デフォルト値を使用して同じ行のダミー読み取りを実行しますIFS。これにより先行スペースが切り捨てられます。コマンド拡張フェーズでは、末尾の改行による衝突を防ぐために、改行ではなくダミー文字を末尾に追加します。印刷するときにはがします。
  • このexprコマンドの目的は、一致する項目の数を見つけることです。この場合、行の前端にあるスペースです。
  • この数値を使用して、適切な設定seqtrコマンドを含む一連のダッシュを作成します。
  • 最後に、trimmedデフォルトのIFSを介して読み取った行でダッシュを印刷します。

関連情報