除以'sed'


40

我正在尝试使用进行数学运算sed,但是它将继续将我的变量视为字符串。输入是这种类型的:

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

我想有15个输出。我只需要执行一次操作并替换其数学结果,因为我将程序作为Python守护程序运行,并且我想避免诸如重定向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'4

我只是认为它可以轻松地转换变量,没有意识到那么复杂!
Luigi Tiburzi 2012年

Answers:


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 2012年

6
有人说编程不是数学。这个小宝石反驳了他们所有人。最佳使用Base 1。
Bruce Ediger

1
好东西!- @Simon:我挑战你实现迭代幂次:P
AT

16
+1这是一个误解与创造力相伴而生的美丽例子。
rozcietrzewiacz 2012年

5
大!我不太了解该语法,但是仅看一下就太棒了!我坚信sed不是要走的路:-),谢谢!!!
Luigi Tiburzi 2012年

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 2012年

克罗斯在这里发布了这个绝妙的答案: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'
格伦·杰克曼


6

我真的不明白为什么接受答案的极端复杂性,以下两种方法都能满足您的要求:

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

要么

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

我认为这可能需要GNU sed,但我不确定。


它是一个gnu扩展。
凯文

好吧,您是对的,但答案不只此而已,它实现的不是一个特定的一般加法,您可以输入任意两个数字,您将得到结果
Luigi Tiburzi

@LuigiTiburzi将其概括为“ x + y”样式的输入非常简单:echo 12+3 | sed -r 's/([0-9]*) *\+ *([0-9]*)/expr \1 + \2/e'
数字创伤

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,只需重击即可:

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

替换每个非数字${var//[^0-9]/}并在双舍入括号中进行算术运算:$((x+3))


2
那里没有bashism。$((...))由POSIX引入(bashism是$[...])。${var//xxx/x}是kshism,也被zsh和bash复制。sed -r是GNUism
斯特凡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

为了克服这一限制,我简单地转向pure sed的内置功能,并实现以下任意长度的十进制加法器:

#!/ 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 /

#十进制全加器模块
#输入:3位数字(输入,A,B,)
#输出:2bits(Carry,Sum)
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
G
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
}
b循环

它的工作方式是实现十进制加法器模块,该模块将两个输入数字(A和B)以及进位位相加,并产生一个总和进位位。这个想法是从电子那里借来的,其中二进制加法器对二进制数字也做同样的事情。我们要做的就是将加法器循环遍历所有数字,然后我们可以添加任意长度的数字(受内存限制)。下面是加法器的作用:

./decAdder.sed
666666666666666666666666666666999999999999991111111112222+1100000000000000000000011111111111111111111111111111111111
1766666666666666666666677777778111111111111102222222223333

可以以完全相同的方式实现二进制(或任何其他基本)加法器。您所要做的就是替换s/$/;000=00001...以给定基础的正确替换模式开头的行。例如:s/$/;000=00001=01010=01011=10100=01101=10110=10111=11/ 是任意长度二进制加法器的替换模式。

您可以适合我github上记录的代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.