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
\G
PCRE一致(幅なし)から前の一致の終わり(//g
コンテキスト内)。したがって、ここでは、^
行の先頭または前の一致の最後に続くスペース(つまり、以前に置き換えられたスペース)を置き換えます。
(この方法はsed
PCREをサポートする実装で使用することもできます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
コマンドの目的は、一致する項目の数を見つけることです。この場合、行の前端にあるスペースです。 - この数値を使用して、適切な設定
seq
とtr
コマンドを含む一連のダッシュを作成します。 - 最後に、
trimmed
デフォルトのIFSを介して読み取った行でダッシュを印刷します。