95595


現在私はPythonで電卓のプログラムを作っています.  
その中で, 入力から受け取った文字列を数学の記号の部分で分割したいのですが, 分割後の処理が楽になるのでリストに記号も残したいです.  
しかし, str.partitionは複数の文字列に対応していません. input()は記号を残せず, eval()は四則演算以外に使えないです.
どなたか良い解決策を教えてください.

**求めている動作:**

[code]

    # 受け取った文字列
    string = "5+14*4"
    
    # (期待する) 分割後の結果
    string_list = ["5", "+", "14", "*", "4"]
    
[/code]


CC BY-SA 4.0
2023-07-13T13:45:23.213
95594
2023-07-14T00:31:44.940
2023-07-14T00:31:44.940
3060
59100
question
python python3
Pythonで区切り文字を残したまま複数の区切り文字で分割する方法

[code]

    import re
    
    string = "5+14*4"
    string_list = re.split(r'\s*([-+*/])\s*', string)
    print(string_list)
    
    # ['5', '+', '14', '*', '4']
    
[/code]


CC BY-SA 4.0
2023-07-13T14:34:36.443
95595
2023-07-13T17:07:46.300
2023-07-13T17:07:46.300
47127
47127
95594
answer


演算記号で分割したいならば`re.split`で複数の記号を使って分割できます。  
さらに空白を取り除きたいならば内包表記で`strip`します。  
さらに複雑な演算を実現するならば正規表現で数字と数字以外を分割します。

**サンプルコード**

[code]

    import re
    
    s = "5+14*4"
    string_list = re.split("([+\-*/])", s)
    print(string_list)
    
    s = "5 + 14 * 4"
    string_list = [x.strip() for x in re.split("([+\-*/])", s)]
    print(string_list)
    
    s = "5 + 14mod4"
    string_list = [x.strip() for x in re.split("([^\d]+)", s)]
    print(string_list)
    
[/code]

**実行結果**

[code]

    ['5', '+', '14', '*', '4']
    ['5', '+', '14', '*', '4']
    ['5', '+', '14', 'mod', '4']
    
[/code]


CC BY-SA 4.0
2023-07-13T14:40:54.847
95596
2023-07-13T14:40:54.847
9820
95594
answer


字句解析ではなく構文解析の方法  
(「電卓」が演算の優先順位あるか不明だけど, あるのだとすれば設計時から考えておいたほうがよいかもしれません)

(Python構文になってしまうが)

[code]

    string = "5+14*4"
    
    import ast
    v = ast.parse(string, mode='eval')
    print(ast.dump(v, indent=4))
    
    # Expression(
    #     body=BinOp(
    #         left=Constant(value=5),
    #         op=Add(),
    #         right=BinOp(
    #             left=Constant(value=14),
    #             op=Mult(),
    #             right=Constant(value=4))))
    
    print('unparse:', ast.unparse(v))
    # unparse: 5 + 14 * 4
    
[/code]

辿り方(の例, のひとつ)

[code]

    for elm in ast.iter_child_nodes(v.body):
        print(elm)
        if isinstance(elm, ast.BinOp):
            print(list(ast.iter_child_nodes(elm)))
    
    # <ast.Constant object at 0x7dd6f4893250>
    # <ast.Add object at 0x7dd71df767a0>
    # <ast.BinOp object at 0x7dd6d341ff10>
    # [<ast.Constant object at 0x7dd6d341f700>, <ast.Mult object at 0x7dd71df76860>, <ast.Constant object at 0x7dd6d341fe20>]
    
[/code]


CC BY-SA 4.0
2023-07-13T15:12:47.657
95597
2023-07-13T15:12:47.657
43025
95594
answer