sed에서의 골프 팁


19

sed에서 골프를 할 때 어떤 일반적인 팁이 있습니까? 코드 골프 문제에 적용 할 수 있고 적어도 sed에 특정한 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).

답변 당 하나의 팁을 게시하십시오.


4
별로 (하지만 여전히 골프를위한 팁)는 골프 팁 : 당신이 당신의 코드를 짧게 유지할 수 있도록 줄 바꿈, 그냥 세미콜론 많은 바이트로 소비 하고 읽을 수 있습니다.
Dennis

팁이 아니라 문제 : 나는 GNU sed를 가지고 있지만 F명령은 결코 작동하지 않았습니다. 아무도 이유를 알고 있습니까?
seshoumara

@seshoumara F는 내 GNU sed (데비안 테스트)에서 작동합니다. -물론 stdin에서 읽는 경우 인쇄 되지만 예상됩니다. 당신은 무엇을 얻 sed -e 'F;Q' /etc/hostname습니까?
Toby Speight

@TobySpeight이 오류가 발생합니다 : char 1: unknown command: F. 아마도 sed를 업데이트해야합니다. 어떤 버전이 있습니까? L명령은 작동하지 않지만, 이후 쓸모 어쨌든이다 -l n존재한다. GNU sed 사이트에 언급 된 모든 내용이 적용됩니다.
seshoumara

1
bash, sed and dc이 언어에 대해 이야기하고 질문하고 싶은 모든 사람들을위한 대화방을 열었습니다 . 커뮤니티를 만들어 보자!
seshoumara

답변:


11

레이블 을 사용해야하는 경우 레이블 이름을 가능한 짧게 만드십시오. 실제로 극단적 인 경우, 빈 문자열을 레이블 이름으로 사용할 수도 있습니다.

:    # define label ""
p    # print pattern space
b    # infinite loop! - branch to label ""

4
gnu sed 4.3에서이 동작은 제거되었습니다 . :이제 라벨이 필요합니다.
케빈

실제로 여기에는 실제 git commit link도 있습니다. PPCG의 경우 GNU sed 4.2.x에 대한 답변을 게시 할 수 있기 때문에 많이 변경되지는 않지만 유감 스럽게도이 트릭이 더 이상 공식적으로 작동하지 않는다는 것을 아는 것이 좋습니다.
seshoumara

8

GNU 나오지 문서는 설명 s등의 명령 "의 sed는 스위스 군용 칼" . 그러나 한 문자의 모든 인스턴스를 다른 문자로 바꾸는 y것만으로도 명령이 필요합니다.

y/a/b/

하나보다 짧은 문자입니다.

s/a/b/g

그것의 방법은 더 빠르고, 문자를 교체 할 수 있습니다 :y/12/21/
mikeserv

6

GNU 정규식에서 확장 정규식 구문 사용을 고려하십시오. 이 -r옵션은 점수를 매기는 데 1 바이트의 비용이 들지만 한 번만 사용하면 한 쌍의 백 슬래시를 제거하여 \(...\)이미 지불했습니다.


2
-rGNU sed고유 의 추가 메모가 있습니다 .
manatwork 2016 년

@manat-추가됨 (하지만 커뮤니티 Wiki 답변이므로 직접 편집 할 수 있음).
Toby Speight

물론이야. 방금 팁의 일부로 간주하지 않고 추가 메모 만 고려했습니다.
manatwork

그리고 그것은 사용할 때 자체에 대한 지불 계속 +, ?, {}|더 백 슬래시가 하나 필요하지 않기 때문에, 정규식 일치한다.
seshoumara

-E내가 올바르게 기억한다면 -r많은 sed구현 에서 별칭으로 작동 합니다.
phk

6

루프에서 반복적으로 교체 할 때 :

loop:
s/foo/bar/g
tloop

루프는 결국 모든 발생을 대체하므로 일반적으로 전역으로 대체 할 필요가 없습니다.

# GNU sed
:
s/foo/bar/
t

위의 GNU 확장도 참고하십시오. 레이블은 빈 이름을 가질 수 있으므로 더 소중한 바이트를 절약 할 수 있습니다. 다른 구현에서, 레이블은 비워 둘 수 없으며 레이블없이 점프하면 플로우가 스크립트의 끝으로 이동합니다 (예 :와 동일 n).


1
빈 레이블 이름은 GNU 전용이며 POSIX에는 스크립트의 끝으로 :
건너 뛸 인수가없는 분기

2
이름없는 레이블은 항상 확장이 아닌 GNU sed의 버그였으며 버전 4.3 이상에서는이 버그가 수정되었습니다. 여기를 참조 하십시오 .
seshoumara

5

내장 된 산술은 없지만 계산은 단항 또는 단항 코딩 된 10 진수로 수행 할 수 있습니다. 다음 코드는 10을 UCD로 변환합니다. x는 단위이고 0은 숫자 구분 기호입니다.

s/[1-9]/0&/g
s/[5-9]/4&/g
y/8/4/
s/9/4&/g
s/4/22/g
s/[37]/2x/g
s/[26]/xx/g
s/[1-9]/x/g

다음은 다시 십진수로의 변환입니다.

s/0x/-x/g
s/xx/2/g
y/x/1/
s/22/4/g
s/44/8/g
s/81/9/g
s/42/6/g
s/21/3/g
s/61/7/g
s/41/5/g
s/-//g

이것들은 모두 "숫자를 사용하지 않고 두 개의 곱하기"에 대한 답변 에서 가져 왔습니다 .

평범한 오래된 단항은 이 답변에서이 루프 쌍을 사용하여 "{Curly Numbers};" 로 변환 할 수 있습니다 . 여기서 단위는 ;입니다. 내가 사용했습니다 vx위해 로마에 맞게 5하고 10, b"비스"에서 온다.

# unary to decimal
:d
/;/{
s/;;;;;/v/g
s/vv/x/g
/[;v]/!s/x\+/&0/
s/;;/b/g
s/bb/4/
s/b;/3/
s/v;/6/
s/vb/7/
s/v3/8/
s/v4/9/
y/;bvx/125;/
td
}

# Decimal to unary
:u
s/\b9/;8/
s/\b8/;7/
s/\b7/;6/
s/\b6/;5/
s/\b5/;4/
s/\b4/;3/
s/\b3/;2/
s/\b2/;1/
s/\b1/;0/
s/\b0//
/[^;]/s/;/&&&&&&&&&&/g
tu

1
... 그리고 당신이 이것들 중 하나를 사용해야한다면, 당신은 자바 코드와 경쟁 할 수 있지만 코드 골프를 거의 잃어 버릴 것입니다.
디지털 외상

일반 단항에서 10 진수로의 변환은 10 진수 형식 X0X에 해당하는 단항 입력에 대해 잘못된 답변을 제공합니다 (예 : 108).이 작업을 수행하는 행은 /[;v]/!s/\b/0/2로 변경 /[;v]/!s:x\+:&0:되어야합니다. 여기를 참조 하십시오 .
seshoumara

@seshoumara, 귀하의 링크는 빈 페이지 인 것 같습니다. 그러나 참조 된 답변에서 해당 코드를 추출 할 때 오류가 발생한 것은 전적으로 그럴듯합니다. 따라서 수정 사항을 적용합니다.
Toby Speight

링크가 올바르게로드되지만 "TIO"가있는 회색 페이지 이외의 것이 예상되고 Ubuntu 로고처럼 보이는 것이 예상되는 것입니까? 그리고 나는 평범한 샘플이 시작된 곳에서 내가 언급 한 두 번째 답변 ( 58007 )을 언급하고 있었습니다 .
Toby Speight

TIO 링크에는 수정 된 코드와 예제 입력 108이 단항으로 포함되어 있어야합니다. 코드를 실행할 때 이전에 수정 된 코드 줄에 의해 이전에 생성 된대로 180이 아닌 올바른 결과 108을 보았을 것입니다. 참조 답변을 업데이트하는 것은 전적으로 귀하에게 달려 있습니다. 이것은 커뮤니티 위키입니다.
seshoumara

4

man sed(GNU) 에서 언급했듯이 구문을 사용하여 모든 문자를 정규식 구분 기호로 사용할 수 있습니다

\%regexp%

여기서 %모든 문자에 대한 자리 표시 자입니다.

이것은 다음과 같은 명령에 유용합니다

/^http:\/\//

어느 것이 더 짧은

\%^http://%

무엇에 언급 GNU 설명서에 나오지도 하지만, 하지 에있는 것은 man sed당신의 구분 기호를 변경할 수 있다는 것입니다 s///y///뿐만 아니라.

예를 들어

ss/ssg

패턴 공간에서 모든 슬래시를 제거합니다.


4

질문에 의해 명시 적으로 금지되지 않은 경우, 이 메타 질문에 대한 합의 는 숫자 입력이 단 항일 수 있다는 것입니다. 이렇게하면 이 답변에 따라 86 바이트의 10 진수가 단항으로 저장됩니다 .


sed에 대한 메타 합의가 일반적인 오래된 단항 형식을 참조하지 않습니까? UCD의 입력이 도움이 될 수있는 몇 가지 대답이 있습니다.
seshoumara

@seshoumara 내가하지 UCD, 단항 의미
디지털 외상

그런 다음 십진수에서 일반 오래된 단항으로 변환하면 연결된 답변에 따라 126 바이트가 절약됩니다. 86 바이트는 UCD로 변환하기위한 것입니다.
seshoumara 2012

4

팁 답변 을 십진수와 일반 단항 형식 간의 변환과 관련하여 확장 하면서 다음과 같은 대체 방법을 장단점으로 제시합니다.

10 진에서 일반 단항으로 : 102 + 1 (r 플래그) = 103 바이트. \t리터럴 탭으로 1 바이트로 계산 했습니다.

h
:
s:\w::2g
y:9876543210:87654321\t :
/ /!s:$:@:
/\s/!t
x;s:-?.::;x
G;s:\s::g
/\w/{s:@:&&&&&&&&&&:g;t}

온라인으로 사용해보십시오!

장점 : 22 바이트 짧고 추가로 음수를 입력으로 사용합니다.

단점 : 보류 공간을 덮어 씁니다. 그러나 프로그램을 시작할 때 입력 정수를 변환해야 할 가능성이 높기 때문에 이러한 제한은 거의 느껴지지 않습니다.

일반 단항에서 10 진수로 : 102 + 1 (r 플래그) = 103 바이트

s:-?:&0:
/@/{:
s:\b9+:0&:
s:.9*@:/&:
h;s:.*/::
y:0123456789:1234567890:
x;s:/.*::
G;s:\n::
s:@::
/@/t}

온라인으로 사용해보십시오!

장점 : 14 바이트 더 짧습니다. 이번에는 두 팁 버전 모두 음수를 입력으로 사용할 수 있습니다.

단점 : 홀드 공간을 덮어 씁니다.

복잡한 문제를 해결하려면이 스 니펫을 수정하여 변환 할 숫자 외에 패턴 공간이나 보유 공간에있을 수있는 다른 정보와 함께 작업해야합니다. 양수로만 작업하거나 0 만 입력이 유효한 입력 / 출력이 아닌 경우 코드를 더 골프화 할 수 있습니다.

이러한 스 니펫을 작성하고 사용한 이러한 챌린지 답변의 예는 숫자역수 (1 / x) 입니다.


단항에서 10 진수의 경우 마지막 두 개의 대체를 결합하여 두 바이트를 절약 할 수 있습니다 s:\n|@$::g. tio.run/##K05N@f@/2ErX3krNwIpL30G/…
Jordan

나는 십진수를 단항 변환기로 시도했다. 여기에 97 바이트가 있습니다 :) 온라인으로 사용해보십시오! (또한 필요하지는 않지만 -r새로운 합의로 플래그는
바이트

실제로 마지막 줄을에서 /\n/ta로 변경 /\n/t하면 1 바이트를 저장하여 96을 얻을 수 있습니다.
Kritixi Lithos

@Cowsquack 감사합니다, 96 훌륭합니다! 지금 시간이 없어 이번 주말에 살펴볼 것입니다.
seshoumara

물론, 채팅에 핑을 보내주세요 :)
Kritixi Lithos

3

tand T명령 에 대해 이야기 해 봅시다 . 맨 페이지에 설명되어 있지만, 특히 코드가 복잡 할 때 잊어 버리고 실수로 버그가 발생하기 쉽습니다.

에 대한 매뉴얼 페이지 설명 t:

s///마지막 입력 행을 읽은 후 마지막 t 또는 T 명령 이후에 a가 성공적인 대체를 수행 한 경우 레이블로 분기하십시오.

의미하는 것을 보여주는 예 : 숫자 목록이 있고 얼마나 많은 음수가 있는지 세고 싶다고합시다. 아래 부분 코드 :

1{x;s/.*/0/;x}                   # initialize the counter to 0 in hold space
s/-/&/                           # check if number is negative
t increment_counter              # if so, jump to 'increment_counter' code block
b                                # else, do nothing (start a next cycle)

:increment_counter
#function code here

괜찮아 보이지만 그렇지 않습니다. 첫 번째 숫자가 양수이면 카운터를 초기화 할 때 t성공적인 s대체 가 있었기 때문에 첫 번째 입력 행에 대한 점프가 수행되기 때문에 해당 코드는 여전히 음수라고 생각합니다 ! 맞습니다 : /-/b increment_counter.

이것이 쉬운 것처럼 보이지만, 함수를 시뮬레이트하기 위해 여러 번 점프를 할 때 여전히 속일 수 있습니다. 이 예에서 increment_counter확실한 코드 블록은 많은 s명령을 사용 합니다. 로 돌아 가면 b main"메인"의 다른 검사가 동일한 트랩에 빠질 수 있습니다. 그래서 나는 보통로 코드 블록에서 돌아온다 s/.*/&/;t label. 추악하지만 유용합니다.


2

GNU sed를 s/.*//사용하는 경우으로 패턴 공간을 지우는 대신 z명령 (소문자)을 사용하십시오 . 적은 바이트 수 외에도 명령 d이 수행하는 것처럼 다음주기를 시작하지 않는 이점이 있으며 , 이는 특정 상황에서 유용 할 수 있습니다.


1
유효하지 않은 멀티 바이트 시퀀스 (와 일치하지 않는 .) 가있는 경우에도 도움이 될 수 있습니다 .
Toby Speight

2

나는 이것이 오래된 스레드라는 것을 알고 있지만, 거의 백 바이트가있는 서투른 10 진수를 UCD 변환기로 찾았습니다 sed.

들어 UCD에 진수 I 이용 (68 바이트, 전 가장 여기에 게시 87 바이트)

s/$/\n9876543210/
:a
s/\([1-9]\)\(.*\n.*\)\1\(.\)/\3x\2\1\3/
ta
P;d

UCD를 10 진수 로 표시합니다 (66 바이트; 전자는 여기 96으로 게시 됨)

s/$/\n0123456789/
:a      
s/\([0-8]\)x\(.*\n.*\)\1\(.\)/\3\2\1\3/
ta      
P;d
  • \n대체품은 휴대 할 수 없습니다. 대신 다른 문자를 사용하여 2 바이트를 저장할 수 있지만 부록 대신에 부록을 제거하려면 더 많은 바이트가 필요합니다 P;d. 다음 말을 참조하십시오. 또는 보류 공간이 비어 있으면 G;s/$/9876543210/바이트 페널티없이 수행하십시오 .
  • 추가 처리가 필요한 경우 s/\n.*//대신 대신 더 많은 바이트가 필요합니다 P;d.
  • 버그가있는 오래된 GNU sed버전에 대해 각각 2 바이트를 절약 할 수 있습니다
  • 아니요, 확장 정규 표현식이 역 참조를 수행하지 않으므로 6 개의 백 슬래시를 저장할 수 없습니다

이 스레드에는 게시 공간을 어지럽히거나 잘못된 sed 버전이 필요한 UCD 및 백 변환기에 대한 10 진수가 없습니다.
seshoumara

4 월 6 일의 답변은 골드 스페이스를 사용 sed하며 POSIX 표준을 위반하는 이전 버전 에서만 실행됩니다 .
Philippos

십진수를 UCD로 변환하지 않습니다! 실을 다시주의해서 읽으십시오. UCD는 12가 0x0xx (답이 계산하는 것)로 변환되는 반면 일반 단항 (응답이 계산하는 것)은 12가 xxxxxxxxxxxx로 변환됨을 의미합니다. @를 기호로 선택했지만 아이디어를 얻습니다. 또한 PPCG에서는 POSIX 표준을 준수 할 필요가 없습니다.
seshoumara

당신을 기쁘게한다면, 보안관
Philippos

2

한 번에 전체 입력을 읽습니다. -z

한 번에 한 줄이 아니라 한 번에 전체 입력을 처리해야하는 경우가 종종 있습니다. 이 N명령은 다음에 유용합니다.

:
$!{N;b}

...하지만 일반적으로 건너 뛰고 -z대신 플래그를 사용할 수 있습니다 .

-z플래그는 나오지 사용 NUL을 (만드는 \0대신 입력 라인 구분자로) \n당신이 당신의 입력이 포함되지 않습니다 알고 있다면 그래서 \0, 그것은 한 번에 하나의 "라인"으로의 입력을 모두 읽습니다 :

$ echo 'foo
> bar
> baz' | sed -z '1y/ao/eu/'
fuu
ber
bez

온라인으로 사용해보십시오!


2

1 바이트로 줄 바꿈 추가

G명령은 줄 바꿈과 보류 공간의 내용을 패턴 공간에 추가합니다. 따라서 보류 공간이 비어 있으면 다음 대신에 :

s/$/\n/

당신은 이것을 할 수 있습니다 :

G

3 바이트의 개행을 추가합니다

H명령은 줄 바꿈과 패턴 공간의 내용을 보류 공간에 추가하고 x둘을 교체하므로 보류 공간이 비어있는 경우 다음 대신에 다음을 수행하십시오.

s/^/\n/

당신은 이것을 할 수 있습니다 :

H;x

이것은 보류 공간을 오염 시키므로 한 번만 작동합니다. 그러나 2 바이트가 더 있으면 스왑하기 전에 패턴 공간을 지울 수 있습니다. 이는 여전히 2 바이트를 절약합니다.

H;z;x

1

sed에서 함수에 가장 가까운 것은 레이블입니다. 함수는 코드를 여러 번 실행할 수 있으므로 많은 바이트를 절약 할 수 있기 때문에 유용합니다. 그러나 sed에서는 리턴 레이블을 지정해야하므로 코드 전체에서이 언어를 다른 언어에서와 같이 여러 번 호출 할 수 없습니다.

내가 사용하는 해결 방법은 반환 메모리를 선택하는 데 사용되는 플래그를 두 메모리 중 하나에 추가하는 것입니다. 함수 코드에 단일 메모리 공간 만 필요한 경우에 가장 효과적입니다 (다른 공간).

내가 의미하는 것을 보여주는 예 : 내 프로젝트에서 가져 와서 작은 게임을 sed로 작성

# after applying the player's move, I overwrite the pattern space with the flag "P"
s/.*/P/
b check_game_status
:continue_turn_from_player
#code

b calculate_bot_move
:return_bot_move
# here I call the same function 'check_game_status', but with a different flag: "B"
s/.*/B/
b check_game_status
:continue_turn_from_bot
#code (like say 'b update_screen')

:check_game_status   # this needs just the hold space to run
#code
/^P$/b continue_turn_from_player
/^B$/b continue_turn_from_bot

레이블은 물론 한 글자 만 골라야합니다. 자세한 설명을 위해 전체 이름을 사용했습니다.


1

빈 정규식은 이전에 발생한 정규식과 같습니다.

( 아나 골 제출 에서 이것을 발견 한 Riley 에게 감사드립니다 )

다음은 @빈 버퍼에 100 초 를 만드는 작업을 수행하는 예 입니다.

s/$/@@@@@@@@@@/;s/.*/&&&&&&&&&&/ # 31 bytes
s/.*/@@@@@@@@@@/;s//&&&&&&&&&&/  # 30 bytes

두 번째 솔루션은 1 바이트 짧으며 빈 정규 표현식이 마지막으로 발생한 정규 표현식으로 채워진다는 사실을 사용합니다. 여기에서 두 번째 대체의 경우 마지막 정규식은 .*이므로 빈 정규식은로 채워집니다 .*. 이것은의 정규 표현식에서도 작동합니다 /conditionals/.

이전에 발생한 정규 표현식이므로 다음도 작동합니다.

s/.*/@@@@@@@@@@/;/@*/!s/$/@/;s//&&&&&&&&&&/

빈 정규 표현식은 도달하지 않기 때문에 @*대신 채워집니다 .$s/$/@/


예, 좋은 대답입니다. 나는 정규식을 더 길게 만들어서 이와 같이 다시 일치시킬 수 있도록했습니다 (따라서 프로그램을 더 짧게 만듭니다).
Toby Speight

0

대부분 쓸모없는 단계 :

y|A-y|B-z|

이 내용은 번역됩니다 AByz(... 그리고 --)하지만, 아무것도, 그래서

sed -e 'y|A-y|B-z|' <<<'Hello world!'

그냥 돌아올 것이다 :

Hello world!

이 낮은 경우의 16 진수 값에이를 이용하여 샘플, 쓸모가있을 것입니다 보장 수 (만 포함 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e또는 f.)


2
이것은 당신이 어려운 길을 찾은 것입니까?! ;-)
Toby Speight

쓸모없는 스크립트와 같은 I : sed '; ;/s/b;y|A-y|B-z|;s ;s/ //; ; ;' <<<'Hello world'(왜 그렇게 하지 공간을 억제?)
F. 하우리
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.