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

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

ただいまの
回答率

90.50%

  • Python

    8013questions

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

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

解決済

回答 7

投稿

  • 評価
  • クリップ 1
  • VIEW 516

cesolution

score 199

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • can110

    2018/06/07 17:46

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

    キャンセル

  • cesolution

    2018/06/07 20:33

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

    キャンセル

回答 7

+4

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

from sympy import sympify, Symbol

symbols = sympify("sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)").atoms(Symbol)
print(symbols)
# {xt, A, x1, b, x2}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/07 20:34

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

    キャンセル

  • 2018/06/07 21:07

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

    キャンセル

checkベストアンサー

+2

正規表現版。

import re

s = 'y = sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)'

funcs = {'sgn', 'sin', 'cos', 'tan', 'max', 'min'}

items = set(filter(None, re.split(r'\W', s)))
ans = items - funcs
print(ans)

関数を列挙しない版。

import re

s = 'y = sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)'

s = re.sub(r'[a-zA-Z]\w+\(', '(', s)

items = set(filter(None, re.split(r'\W', s)))

items = [v for v in items if not re.match(r'^[0-9]', v)]

print(items)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/08 07:29

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

    キャンセル

  • 2018/06/08 09:35

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

    キャンセル

  • 2018/06/08 14:03

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

    キャンセル

  • 2018/06/08 14:45

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

    キャンセル

+2

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

y = m(a+b)

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

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

そして、ルールを増やす

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

y = m*(a+b)

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

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

そして、ルールを増やす

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

y = sgn(A*sin(x1+b))+b*cos(max(x2,xt)+2*b)
といった式の中から
変数:x1、x2
定数:A、、b、xt
を取り出したいと考えています。

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

とりあえず

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/07 20:36

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

    キャンセル

+2

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

y=sgn(A*sin(x1+b))+b*cos(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 20:34

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

    キャンセル

+1

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

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

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


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

(+ (sgn (* A 
        (sin (+ x1 b))))
   (* b 
      (cos (+ (max x2 xt)
              (* 2 b)))))

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    8013questions

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