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이거나 너비가 두 개인 문자( [: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"-"
- 대체 하위 문자열 구성
선택하다파이썬3.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
파일을 한 줄씩 읽도록 루프를 설정 하고IFS
로 설정합니다NULL
. 이것의 목적은 줄의 모든 공백을 유지하는 것입니다.- 다음으로 기본값을 사용하여 동일한 행의 더미 읽기를 수행합니다
IFS
. 이렇게 하면 선행 공백이 잘립니다. 명령 확장 단계에서 후행 줄 바꿈으로 인한 충돌을 방지하기 위해 줄 바꿈이 아닌 더미 문자를 끝에 추가합니다. 인쇄할 때 벗겨냅니다. - 이
expr
명령의 목적은 일치하는 항목의 수를 찾는 것입니다. 이 경우에는 줄의 앞쪽 가장자리에 있는 공백입니다. - 이 숫자를 사용하여 적절한 설정
seq
과tr
명령이 포함된 일련의 대시를 생성합니다. - 마지막으로
trimmed
기본 IFS를 통해 읽은 줄과 함께 대시를 인쇄합니다.