'sed'를 사용한 추가


40

로 수학 연산을 수행하려고 sed하지만 변수를 문자열로 계속 처리합니다. 입력은 다음과 같습니다.

$ echo 12 | sed 's/[0-9]*/&+3/'
$ 12+3

출력으로 15를 갖고 싶습니다. 파이썬 데몬으로 프로그램을 실행하고 있기 때문에 작업을 수행하고 수학 결과를 한 번만 대체해야하며 stdout파일 리디렉션 , 파일 열기, 작업 수행, 결과 추출, 수행 과 같은 구절을 피하고 싶습니다. 대체품. 나에게 sed한 줄로 모든 것을 수행하는 것이 가장 좋습니다.

입력과 출력을 모두 다양한 방법으로 캐스팅하려고했습니다.

$ echo 12 | sed 's/[0-9]*/int(&+3)/'
$ echo 12 | sed 's/[0-9]*/\int(&+3)/'
$ echo 12 | sed 's/[0-9]*/\int(&+3)/'

그러나 결과는 항상 두 번째 필드의 인쇄였습니다.


12
"변수"를 문자열로 취급합니다. 왜냐하면 모든 것이 sed이기 때문입니다-문자열 조작. "정수"라는 개념이 없습니다.
케빈

2
sed수학 을하기 위해 사용하고 싶은지 궁금합니다
David Oneill

방금 변수를 쉽게 캐스팅 할 수 있다고 생각했지만 너무 복잡하다는 것을 알지 못했습니다!
Luigi Tiburzi

답변:


82

정직하게 sed를 사용하려면 다음과 같이하십시오.

s/[0-9]/<&/g
s/0//g; s/1/|/g; s/2/||/g; s/3/|||/g; s/4/||||/g; s/5/|||||/g; s/6/||||||/g
s/7/|||||||/g; s/8/||||||||/g; s/9/|||||||||/g
: tens
s/|</<||||||||||/g
t tens
s/<//g
s/+//g
: minus
s/|-|/-/g
t minus
s/-$//
: back
s/||||||||||/</g
s/<\([0-9]*\)$/<0\1/
s/|||||||||/9/; s/||||||||/8/; s/|||||||/7/; s/||||||/6/; s/|||||/5/; s/||||/4/
s/|||/3/; s/||/2/; s/|/1/
s/</|/g
t back

입력:

1+2
100+250
100-250

산출:

3
350
-150

당신의 임무는 그것을 받아들이기로 선택하면 곱셈을 구현하는 것입니다.


5
도전에 +1하세요! 어쩌면 그 무언가 것 코드 골프 ;-p
Tatjana Heuser 씨

6
그리고 어떤 사람들은 프로그래밍이 수학이 아니라고 말합니다. 이 작은 보석은 그들 모두를 반박합니다. Base 1을 최대한 활용하십시오.
Bruce Ediger

1
좋은 것! -@Simon : 나는 당신이 tetration : P
AT

16
+1 이것은 창의성과 짝을 이루는 오해가 번식 할 수있는 아름다운 예입니다.
rozcietrzewiacz

5
큰! 나는 구문을 잘 이해하지 못하지만 그것을 보는 것만으로도 훌륭합니다! 나는 sed가 갈 길이 아니라고 확신합니다 :-), 감사합니다 !!!
Luigi Tiburzi

20

sed여기서 가장 좋은 옵션은 아니지만 기본적으로 산술을 수행하지 않습니다 ( 가능한 방법 은 숫자 증가 참조 ). 당신은 그것을 할 수 있습니다 awk:

$ echo 12 | awk '{print $0+3}'
15

사용하는 가장 좋은 코드는 입력의 정확한 형식과 숫자가 아니거나 두 개 이상의 숫자가 포함 된 경우 수행하려는 작업에 따라 다릅니다.

당신은 또한 다음과 bash같이 할 수 있습니다 :

$ echo $(( $(echo 12) + 3 ))

또는 expr비슷한 방식으로 사용합니다.


17

@Richter의 도전을 받아들이려고했습니다. 이것은 코드의 일부를 사용하여 수행 한 것입니다.

sed 's/[0-9]/<&/g
s/0//g; s/1/|/g; s/2/||/g; s/3/|||/g; s/4/||||/g; s/5/|||||/g; s/6/||||||/g
s/7/|||||||/g; s/8/||||||||/g; s/9/|||||||||/g
: tens
s/|</<||||||||||/g
t tens
s/<//g
s/.*\*$/0/
s/^\*.*/0/
s/*|/*/
: mult
s/\(|*\)\*|/\1<\1*/ 
t mult
s/*//g
s/<//g
: back
s/||||||||||/</g
s/<\([0-9]*\)$/<0\1/
s/|||||||||/9/; s/||||||||/8/; s/|||||||/7/; s/||||||/6/; s/|||||/5/; s/||||/4/
s/|||/3/; s/||/2/; s/|/1/
s/</|/g
t back'

입력:

04*3
4*3
40*3
42*32
150*20
1*3
3*1
0*3
3*0

출력 : 모든 올바른 결과


@SimonRichter 당신이 즐기시기 바랍니다!
Luigi Tiburzi

Cross는이 훌륭한 답변을 여기에 게시했습니다 : codegolf.stackexchange.com/a/39882/11259
Digital Trauma

12

perl매우 유사한 구성을 허용합니다 sed... 한 가지 차이점은 perl더 복잡한 일 을 할 수 있다는 것입니다 ... sed간단한 텍스트 인쇄물에 매우 좋습니다

 echo 'a12' | perl -pe 's/([0-9]+)/($1+3)/e'  # the trailing /e means evaluate

산출

a15

2
또한 캡처 괄호없이이 작업을 수행 할 수 있습니다perl -pe 's/[0-9]+/$&+3/e'
글렌 잭맨

8

그냥 문자열을 계산기에 넣습니다

 echo 12 | sed 's/[0-9]*/&+3/' | bc

숫자 사이에 텍스트가 있으면 작동하지 않습니다.
glenn jackman

6

나는 정말로 아래의 대답 중 하나가 당신이 원하는 것을 받아들이는 이유가 무엇인지 이해하지 못합니다.

echo 12 | sed 's/[0-9]*/echo \$(( & + 3 ))/e'

또는

echo 12 | sed 's/[0-9]*/expr & + 3/e'

GNU sed가 필요할 수도 있지만 확실하지 않습니다.


gnu 확장입니다.
Kevin

좋아 당신이 맞지만 대답은 넘어갑니다, 그것은 특정 추가가 아닌 일반적인 추가를 구현합니다. 두 숫자를
먹이면

@LuigiTiburzi 이것을 "x + y"스타일 입력으로 일반화하는 것은 매우 간단합니다 :echo 12+3 | sed -r 's/([0-9]*) *\+ *([0-9]*)/expr \1 + \2/e'
Digital Trauma

5

정규식과 산술 연산을 확실히 결합해야하는 경우 정규식의 대체 매개 변수가 콜백 함수가 될 수있는 언어를 선택하십시오.

Perl, Ruby, JavaScript 및 Python은 다음과 같은 언어입니다.

bash-4.2$ echo 12 | perl -pe 's/\d+/$&+3/e'
15

bash-4.2$ echo 12 | ruby -pe '$_.sub!(/\d+/){|s|s.to_i+3}'
15

bash-4.2$ echo 12 | js -e 'print(readline().replace(/\d+/,function(s){return parseInt(s)+3}))'
15

bash-4.2$ echo 12 | python -c 'import re;print re.sub("\d+",lambda s:str(int(s.group(0))+3),raw_input())'
15

1

bash실제로 파이프에서 작동하는 또 다른 간단한 솔루션 :

 echo 12 | { read num; echo $(( num + 3)); }

1

bashism을 혼합하면 :

echo $(($(echo 12 | sed 's/[0-9]*/&+3/')))

텍스트에서 숫자를 추출하려면

echo $(($(echo "foo12bar" | sed -r 's/[^0-9]*([0-9]*).*/\1+3/')))

sed가 없으면 bash를 사용하십시오.

var="foo12bar"
echo $((${var//[^0-9]/}+3))

숫자 ${var//[^0-9]/}가 아닌 모든 숫자를 대체하고 이중 라운드 파 렌스에서 산술을 수행합니다.$((x+3))


2
거기에 bashism이 없습니다. $((...))POSIX에 의해 소개되었습니다 (bashism은 $[...]). ${var//xxx/x}zsh 및 bash에 의해 복사 된 kshism입니다. sed -r은 GNUism입니다
Stéphane Chazelas

0

Perl 솔루션은 다음과 같습니다.

echo 12 | perl -wlpe '$_ += 3'
# Output:  15

문자열에서 발견 된 첫 번째 숫자 세트를 변경하려면 다음을 사용할 수 있습니다.

echo I am 12 years old. | perl -wlpe 's/(\d+)/$1 + 3/e'
# Output:  I am 15 years old.

문자열에서 모든 숫자 세트 를 변경 하려면 다음 /g과 같이 수정자를 사용할 수 있습니다 .

echo They are 11, 12, and 13 years old. | perl -wlpe 's/(\d+)/$1 + 3/eg'
# Output:  They are 14, 15, and 16 years old.

0

sed 표현을 사용하는 것은 훌륭하지만 한계가 있습니다. 예를 들어 다음은 실패합니다.

$ echo "1000000000000000000000000000000+1" | sed -e 's/\([0-9]*\)+\([0-9]*\)/expr \1 + \2/e'
expr: 1000000000000000000000000000000: Numerical result out of range

이 한계를 극복하기 위해 순수 sed의 내장 기능을 켜고 다음과 같이 임의 길이의 10 진수 가산기를 구현하십시오.

#! / bin / sed -f

s / + / \ n / g
s / $ / \ n \ n0 /

:고리
s / ^ \ (. * \) \ (. \) \ n \ (. * \) \ (. \) \ n \ (. * \) \ n \ (. \) $ / 0 \ 1 \ n0 \ 3 \ n \ 5 \ n \ 6 \ 2 \ 4 /
h
s /^.* \ n. * \ n. * \ n \ (... \) $ / \ 1 /

10 진수 완전 가산기 모듈
# 입력 : 3 자리 (반입, A, B,)
# 출력 : 2 비트 (수행, 합계)
s / $ /;000 = 00001 = 01002 = 02003 = 03004 = 04005 = 05006 = 06007 = 07008 = 08009 = 09010 = 01011 = 02012 = 03013 = 04014 = 05015 = 06016 = 07017 = 08018 = 09019 = 10020 = 02021 = 03022 = 04023 = 05024 = 06025 = 07026 = 08027 = 09028 = 10029 = 11030 = 03031 = 04032 = 05033 = 06034 = 07035 = 08036 = 09037 = 10038 = 11039 = 12040 = 04041 = 05042 = 06043 = 07044 = 08045 = 09046 = 10047 = 11048 = 12049 = 13050 = 05051 = 06052 = 07053 = 08054 = 09055 = 10056 = 11057 = 12058 = 13059 = 14060 = 06061 = 07062 = 08063 = 09064 = 10065 = 11066 = 12067 = 13068 = 14069 = 15070 = 07071 = 08072 = 09073 = 10074 = 11075 = 12076 = 13077 = 14078 = 15079 = 16080 = 08081 = 09082 = 10083 = 11084 = 12085 = 13086 = 14087 = 15088 = 16089 = 17090 = 09091 = 10092 = 11093 = 12094 = 13095 = 14096 = 15097 = 16098 = 17099 = 18100 = 01101 = 02102 = 03103 = 04104 = 05105 = 06106 = 07107 = 08108 = 09109 = 10110 = 02111 = 03112 = 04113 = 05114 = 06115 = 07116 = 08117 = 09118 = 10119 = 11120 = 03121 = 04122 = 05123 = 06124 = 07125 = 08126 = 09127 = 10128 = 11129 = 12130 = 04131 = 05132 = 06133 = 07134 = 08135 = 09136 = 10137 = 11138 = 12139 = 13140 = 05141 = 06142 = 07143 = 08144 = 09145 = 10146 = 11147 = 12148 = 13149 = 14150 = 06151 = 07152 = 08153 = 09154 = 10155 = 11156 = 12157 = 13158 = 14159 = 15160 = 07161 = 08162 = 09163 = 10164 = 11165 = 12166 = 13167 = 14168 = 15169 = 16170 = 08171 = 09172 = 10173 = 11174 = 12175 = 13176 = 14177 = 15178 = 16179 = 17180 = 09181 = 10182 = 11183 = 12184 = 13185 = 14186 = 15187 = 16188 = 17189 = 18190 = 10191 = 11192 = 12193 = 13194 = 14195 = 15196 = 16197 = 17198 = 18199 = 19 /
s / ^ \ (... \) [^;] *; [^;] * \ 1 = \ (.. \). * / \ 2 /
H
지
s / ^ \ (. * \) \ n \ (. * \) \ n \ (. * \) \ n ... \ n \ (. \) \ (. \) $ / \ 1 \ n \ 2 \ n \ 5 \ 3 \ n \ 4 /
/ ^ \ ([0] * \) \ n \ ([0] * \) \ n / {
        s /^.* \ n. * \ n \ (. * \) \ n \ (. \) / \ 2 \ 1 /
        s / ^ 0 \ (. * \) / \ 1 /
        큐
}
b 루프

작동 방식은 Carry Bit와 함께 두 개의 입력 숫자 (A 및 B)를 더하고 Sum 및 Carry 비트를 생성하는 10 진수 가산기 모듈을 구현하는 것입니다. 이진 가산기이진수에 대해 동일한 기능을 수행하는 전자에서 아이디어를 얻습니다. 우리가해야 할 일은 모든 숫자에 가산기를 반복하고 임의의 길이의 숫자를 추가 할 수 있다는 것입니다 (메모리에 의해 제한됨). 다음은 가산기가 작동하는 모습입니다.

./decAdder.sed
666666666666666666666666666666999999999999991111111112222+1100000000000000000000011111111111111111111111111111111111
1766666666666666666666677777778111111111111102222222223333

정확히 같은 방식으로 바이너리 (또는 다른 기본) 가산기를 구현할 수 있습니다. s/$/;000=00001...주어진베이스에 대한 적절한 대체 패턴으로 시작하는 라인을 교체하기 만하면됩니다 . 예를 들어 : s/$/;000=00001=01010=01011=10100=01101=10110=10111=11/ 임의 길이 이진 가산기의 대체 패턴입니다.

내 github에 문서화 코드를 맞출 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.