เพิ่มเติมด้วย 'sed'


40

ฉันพยายามดำเนินการทางคณิตศาสตร์ด้วยsedแต่ก็ยังคงรักษาตัวแปรของฉันเป็นสตริง อินพุตเป็นแบบนี้:

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

ฉันต้องการที่จะมี 15 เป็นเอาท์พุท ฉันต้องทำการดำเนินการและแทนที่ผลลัพธ์ทางคณิตศาสตร์ในข้อความเดียวเท่านั้นเพราะฉันกำลังเรียกใช้โปรแกรมเป็น Python daemon และฉันต้องการหลีกเลี่ยงข้อความเช่นการเปลี่ยนเส้นทาง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
มันคือการรักษา "ตัวแปร" ของคุณเป็นสตริงเพราะนั่นคือทั้งหมดที่ทำ - การจัดการสตริง ไม่มีแนวคิดของ "จำนวนเต็ม"
เควิน

2
ฉันอยากรู้อยากเห็นมากว่าทำไมคุณต้องการที่จะใช้sedในการทำคณิตศาสตร์
เดวิด 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 สำหรับความท้าทายรักมัน! อาจจะเป็นสิ่งที่Code Golf ;-p
Tatjana Heuser

6
และบางคนบอกว่าการเขียนโปรแกรมไม่ใช่คณิตศาสตร์ อัญมณีตัวนี้หักล้างพวกเขาทั้งหมด การใช้งาน Base 1 ที่ดีที่สุด
Bruce Ediger

1
ทำได้ดีนี่! - @Simon: ฉันขอท้าให้คุณใช้การทดลอง : 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ดีมากสำหรับ substitions ข้อความธรรมดา

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

เอาท์พุต

a15

2
นอกจากนี้ยังสามารถทำเช่นนี้ได้โดยไม่ต้องวงเล็บจับ:perl -pe 's/[0-9]+/$&+3/e'
เกล็น Jackman


6

ฉันไม่เข้าใจว่าทำไมความซับซ้อนของคำตอบที่ได้รับการยอมรับอย่างใดอย่างหนึ่งดังต่อไปนี้ทำในสิ่งที่คุณต้องการ:

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

หรือ

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

ฉันคิดว่ามันอาจต้องใช้ GNU sed แต่ฉันไม่แน่ใจ


มันเป็นนามสกุล gnu
Kevin

โอเคคุณพูดถูก แต่คำตอบนั้นเกินกว่านั้นมันใช้การเพิ่มทั่วไปไม่ใช่แบบเฉพาะคุณสามารถป้อนตัวเลขสองตัวใดก็ได้และคุณจะได้ผลลัพธ์
Luigi Tiburzi

@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

หากคุณผสมใน bashism บางอย่าง:

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

หากต้องการแยกตัวเลขออกจากข้อความ:

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

โดยไม่ต้อง sed เพียงแค่ทุบตี:

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

แทนที่ทุกตัวเลขที่ไม่ใช่ดิจิต${var//[^0-9]/}และทำเลขคณิตใน parens คู่รอบ:$((x+3))


2
ไม่มีการทุบตีในนั้น $((...))ถูกแนะนำโดย POSIX (bashism คือ$[...]) ${var//xxx/x}เป็น kshism ยังคัดลอกโดย zsh และ bash 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

แม้ว่าการใช้การแสดงออกที่ยอดเยี่ยมนั้นยอดเยี่ยม แต่ก็มีข้อ จำกัด ตัวอย่างต่อไปนี้ล้มเหลว:

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

ในการเอาชนะข้อ จำกัด นี้เพียงแค่ฉันหันไปใช้อำนาจของ sed บริสุทธิ์ในตัวและดำเนินการตาม adder ทศนิยมความยาวตามอำเภอใจ:

#! / bin / sed -f

S / + / \ n / g
s / $ / \ n \ N0 /

: LOOP
s / ^ \ (. * \) \ (. \) \ n \ (. * \) \ (. \) \ n \ (. * \) \ n \ (. \) $ / 0 \ 1 \ n0 \ 3 \ n \ 5 \ n \ 6 \ 2 \ 4 /
ชั่วโมง
s /^.* \ n. * \ n. * \ n \ ( ... \) $ / \ 1 /

# โมดูล adder เต็มทศนิยม
# INPUT: 3 หลัก (Carry in, 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 /
        Q
}
ขลูป

วิธีการทำงานคือการใช้โมดูล adder ทศนิยมที่เพิ่มตัวเลขสองหลัก (A และ B) เช่นเดียวกับ Carry บิตและผลิตบิตและผลรวม แนวคิดนี้ยืมมาจากอิเล็กทรอนิกส์โดยที่ตัวบวกเลขฐานสองนั้นเหมือนกันสำหรับเลขฐานสอง สิ่งที่เราต้องทำคือวนลูป adder เหนือตัวเลขทั้งหมดและเราสามารถเพิ่มความยาวตามอำเภอใจ (จำกัด โดยหน่วยความจำ) ด้านล่างคือ adder ที่ทำงาน:

./decAdder.sed
666666666666666666666666666666999999999999991111111112222+1100000000000000000000011111111111111111111111111111111111
1766666666666666666666677777778111111111111102222222223333

ในลักษณะเดียวกับที่คน ๆ หนึ่งสามารถนำไปใช้กับตัวบวกไบนารี (หรือฐานอื่น ๆ ) สิ่งที่คุณต้องทำคือแทนที่บรรทัดที่ขึ้นต้นด้วยs/$/;000=00001...รูปแบบการทดแทนที่เหมาะสมสำหรับฐานที่กำหนด ตัวอย่างเช่น: s/$/;000=00001=01010=01011=10100=01101=10110=10111=11/ เป็นรูปแบบการทดแทนสำหรับ adder ไบนารีความยาวโดยพลการ

คุณสามารถใส่รหัสลงใน GitHub ของฉันได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.