web-dev-qa-db-ja.com

「sed」を使用した加算

sedを使用して数学演算を実行しようとしていますが、変数を文字列として扱い続けています。入力は次の種類です:

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

出力として15が必要です。 Pythonデーモンとしてプログラムを実行しており、stdoutのリダイレクトなどのパッセージを回避したいファイルでは、それらのファイルを開き、操作を実行し、結果を抽出し、置換を行います。私にとって、sedはすべてを1行で実行するのが最善のようです。

私はさまざまな方法で入力と出力の両方をキャストしようとしました

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

しかし、結果は常に2番目のフィールドの印刷でした。

41
Luigi Tiburzi

あなたが正直に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

あなたの使命は、それを受け入れることを選択した場合、乗算を実装することです。

84
Simon Richter

sedは、ここでの最良のオプションではありません。ネイティブで算術を実行しません(ただし、可能性のある方法については 数値をインクリメント を参照してください)。あなたはawkでそれを行うことができます:

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

使用するのに最適なコードは、入力の正確な形式と、数値ではない場合、または複数の数値が含まれている場合などに、何をしたいか/何をしたいかによって異なります。

bashでのみこれを行うこともできます:

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

または、exprを同様の方法で使用します。

21
Mat

私はあなたの挑戦@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

出力:すべての正しい結果

17
Luigi Tiburzi

Perlsedと非常によく似た構成を許可します... 1つの違いはPerlがより複雑なことを実行できることです... sedは単純なテキスト置換

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

出力

a15
12
Peter.O

文字列を計算機に入力するだけです

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

受け入れられた回答の極端な複雑さ、以下のいずれかがあなたが望むことをする理由は本当にわかりません:

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

または

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

GNU sedが必要かもしれませんが、よくわかりません。

6
michelpm

正規表現と算術演算を組み合わせる必要がある場合は、正規表現の置換パラメータがコールバック関数になる言語を選択してください。

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
5
manatwork

別の単純なbashソリューション。これは実際にパイプで機能します。

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

いくつかのバシズムを混ぜると:

_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))

1
user unknown

これが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.

文字列内の数字のセットallを変更する場合は、次のように/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
J-L

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 /
 
:LOOP 
 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 
 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ループ

それが機能する方法は、2つの入力桁(AとB)とキャリービットを加算し、合計とキャリービットを生成する10進加算モジュールを実装することです。このアイデアは電子工学から借用されたもので、 binary adder が2進数に対して同じことを行います。必要なのは、すべての桁で加算器をループすることであり、任意の長さの数値を追加できます(メモリによって制限されます)。以下は、動作中の加算器です。

./decAdder.sed
666666666666666666666666666666999999999999991111111112222+1100000000000000000000011111111111111111111111111111111111
1766666666666666666666677777778111111111111102222222223333

まったく同じ方法で、バイナリ(またはその他のベース)加算器を実装できます。 s/$/;000=00001...で始まる行を、指定されたベースの適切な置換パターンに置き換えるだけです。例:s/$/;000=00001=01010=01011=10100=01101=10110=10111=11/は、任意の長さのバイナリ加算器の置換パターンです。

文書化されたコード my github上 を適合させることができます。

0
Emsi