質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

7回答

1032閲覧

式中の変数のみを抽出する方法について

cesolution

総合スコア217

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2018/06/07 07:55

現在、Pythonでユーザーが入力した複数の式の中から変数、定数(係数は除きます)のみを抽出することを考えています。
例えば、
y = sgn(Asin(x1+b))+bcos(max(x2,xt)+2*b)
といった式の中から
変数:x1、x2
定数:A、、b、xt
を取り出したいと考えています。

式を文字列として読み込んで、=、*、-、+、/,(、)等を区切り文字とし、関数名や数字を除けば良いかとも考えましたが、max関数やsin、cos、acos、cosh等、考えられる関数の数がかなり多く、ユーザーがどのような入力をするか分からないため、上記の方法では難しそうで、現在息詰まっております。(上式は一例で、実際にユーザーがどのような形で式を入力するかは様々なケースがあり得ます)
もう少し考えてみますが、良い案をお持ちの方がいらっしゃいましたら、アイディアだけでも構いませんので、ご教授いただければ幸いです。

宜しくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2018/06/07 08:46

式の構文規則は定まっていますか?また提示式にて変数と定数の区別はどのような規則で行っていますか?
cesolution

2018/06/07 11:33

式の構文規則はある程度定まっております。変数と定数は分ける必要はないのですが、数値とは分ける必要がある形です。
guest

回答7

0

Sympy を使うとよいのではないでしょうか。

Python

1from sympy import sympify, Symbol 2 3symbols = sympify("sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)").atoms(Symbol) 4print(symbols) 5# {xt, A, x1, b, x2}

投稿2018/06/07 09:30

magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cesolution

2018/06/07 11:34

ありがとうございます。なるほど、SympyだとSymbolを抜き出すことができるんですね。勉強になります。
wakame

2018/06/07 12:07

parserを使って・・・とやろうとしたらこんなやり方もあるのですね、勉強になります。
guest

0

ベストアンサー

正規表現版。

python

1import re 2 3s = 'y = sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)' 4 5funcs = {'sgn', 'sin', 'cos', 'tan', 'max', 'min'} 6 7items = set(filter(None, re.split(r'\W', s))) 8ans = items - funcs 9print(ans)

関数を列挙しない版。

python

1import re 2 3s = 'y = sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)' 4 5s = re.sub(r'[a-zA-Z]\w+(', '(', s) 6 7items = set(filter(None, re.split(r'\W', s))) 8 9items = [v for v in items if not re.match(r'^[0-9]', v)] 10 11print(items)

投稿2018/06/07 09:43

編集2018/06/07 10:03
mkgrei

総合スコア8560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cesolution

2018/06/07 22:29

アイディアだけでなく具体的なコードまでご提示いただきありがとうございました。
cesolution

2018/06/08 00:35

re関数非常に便利ですね。こちらの対応方法で工夫すればできそうです。ベストアンサーを選び間違えてしまいすみません、非常に助かりました。
LouiS0616

2018/06/08 05:03

ベストアンサーは、後から付け替えることも可能です。 もし『厳密には出来ない』という私の回答より『やるならばこう』というmkgreiさんの回答の方がお好みならば、今から付け替えても良いかと思います。
cesolution

2018/06/08 05:45

LouiS0616様、ご連絡ありがとうございます。頭を整理する上でご指摘いただいた内容が参考になったのですが、その上で方針を決めて実際に組む段になってmkgrei様のご提案が参考になったため、ベストアンサーを付け替えさせていただきたいと思います。
guest

0

  1. まず文字列全体から空白文字を削除する

y=sgn(Asin(x1+b))+bcos(max(x2,xt)+2*b)

  1. 連続するアルファベットの右側に'('があるパターンから関数名を検索して当該部分を削除する

y=(A*(x1+b))+b*((x2,xt)+2*b)

  1. 変数と定数以外(アルファベットと数字以外の文字)の文字をすべて空白にする

y A x1 b b x2 xt 2 b

  1. 一つ以上の連続する空白を ',' に置き換える

y,A,x1,b,b,x2,xt,2,b

こんな感じでできそうですがいかがでしょうか。
正規表現使えば各ステップは難しくないと思います。
なお、ユーザー定義関数だけ残したい場合は、予約語を辞書で持っておく必要があると思います。
また、変数と定数の区別については、命名規則がハッキリしていないと区別できないでしょう。

ご参考になれば。

投稿2018/06/07 08:40

tkanda

総合スコア2425

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cesolution

2018/06/07 11:34

非常にスッキリ整理していただきありがとうございます。大変参考になります。
guest

0

例えば、こんな入力があったとします。

plain

1y = m(a+b)

これは、mという関数にa+bを与えているのでしょうか。
あるいは、mという値を、a+bの結果に掛け合わせようとしているのでしょうか。

これだけ見れば判別不可能です。

そして、ルールを増やす

これを防ぐために、『乗算記号の省略は認めない』というルールを作るとします。
先ほどの入力が、次のように修正されたとします。

plain

1y = m*(a+b)

この式のmは、変数でしょうか。あるいは、定数でしょうか。
また、aやbは絶対に定数であると、誰が保証してくれるのでしょうか。

これだけ見れば判別不可能です。
ユーザが定数と主張すればそれは定数でしょうし、変数と主張すればそれは変数です。

そして、ルールを増やす

変数は必ずx, y あるいは z から始まるとし、それ以外を定数とします。

y = sgn(Asin(x1+b))+bcos(max(x2,xt)+2*b)

といった式の中から
変数:x1、x2
定数:A、、b、xt
を取り出したいと考えています。

前述のルールに則ればxtは変数になってしまいます。
さて、どのように変数と定数を区別できるとお考えなのでしょうか。

とりあえず

区別したいのなら、最低限明確な命名規則を決めるべきかと思います。

また、利用可能な文字も制限する必要があります。
たとえば、log_10という関数を許すか?などなど。

投稿2018/06/07 08:15

編集2018/06/07 08:21
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cesolution

2018/06/07 11:36

非常に明快なご回答ありがとうございます。あやふやな部分が明確になってきましたので、こちらを参考に詰めていきたいと思います。皆様非常に参考になるコメントをいただきありがとうございました。
guest

0

数式表現なんて人間が文脈を見て意味を判断する自然言語なので、はっきり言って式だけ入れてもまともに解析なんてできません。

  • 変数名、定数名、関数名は先に宣言させる

という発想で挑まないと厳しいと思うのですが、そうする訳にはいきませんか。
逆に、そういう仕様にしてしまえば、組み込みで適当な名前を提供するとかは自由です。


いっそ「S式で入力してくれ」という話にはならないものか。

lisp

1(+ (sgn (* A 2 (sin (+ x1 b)))) 3 (* b 4 (cos (+ (max x2 xt) 5 (* 2 b))))) 6

投稿2018/06/07 10:44

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

はっきり言って不可能だと思います。

ユーザーがどのような入力をするか分からないため

とあるので、規則がありません。
規則がない場合、コードできません。
規則を作ってそれに乗っ取った式かどうかは解析できますが、そうでなければ
解析できません。
AIを使って、これは変数の確率89%みたいな表現で類推する方法もあります。
が、この方法も大変でしょうね。
規則を作った方が良いと思います。

投稿2018/06/07 10:51

ikapy

総合スコア1167

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

~~ 関数の途中の計算結果を再利用したい場合 - teratail ~~

↑これじゃまずいんですかね?

追記:
質問の内容を勘違いしていました。
回答を取り下げます。

投稿2018/06/07 08:22

編集2018/06/07 08:43
tkturbo

総合スコア5572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問