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

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

ただいまの
回答率

88.33%

括弧が複数階層の文字列の階層ごとに分割したい

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 710

contact2093

score 5

前提・実現したいこと

次のようになっているものを,全て分割したいです。
input
((((AAA,BBB),CCC)DDD), (EEE,FFF))
output
(AAA,BBB)
((AAA,BBB),CCC)
(((AAA,BBB),CCC),DDD)
(EEE,FFF)
((((AAA,BBB),CCC)DDD), (EEE,FFF))

試したこと

一番小さい括弧は取れました。
そのあと大きくしていく方法がわかりません。
そして,テストデータは括弧が最大4個ですが,n階層になっても大丈夫なようにしたいです。
よろしくお願いします。

該当のソースコード

python3
import re

A = "((((AAA,BBB),CCC)DDD), (EEE,FFF))"
B = re.findall("\([^()]+\)",A)

for i in B:
print(i)
>>(AAA,BBB)
>>(EEE,FFF)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+2

入力文字列を先頭から順にスキャンして:

  • 開きカッコだった場合
    → スタックに位置を記憶しておく(これが文字列切り出しの開始位置になる)

  • 閉じカッコだった場合
    → スタックから対応する開きカッコの位置を取り出して、そこから現在位置までの文字列を切り出す

というアプローチではどうでしょうか。

s = '((((AAA,BBB),CCC),DDD), (EEE,FFF))'

stack = []
result = []
for i, ch in enumerate(s):
    if ch == '(':
        stack.append(i)
    elif ch == ')':
        result.append(s[stack.pop():i + 1])

print(*result, sep='\n')

# (AAA,BBB)
# ((AAA,BBB),CCC)
# (((AAA,BBB),CCC),DDD)
# (EEE,FFF)
# ((((AAA,BBB),CCC),DDD), (EEE,FFF))

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/27 18:36

    一番簡潔だったので,こちらを採用しました。ありがとうございました。

    キャンセル

+2

再帰的にn階層たどるような場合、正規文法では表せず、文脈自由文法が要ります(チョムスキー階層より)。

適当に文法の定義っぽいものを書いて考えてみます。

node: "(" (node | symbol) "," (node | symbol) ")"
symbol: "[A-F]{3}"

みるからにLL(1)の文法です。簡単そうなので再帰下降構文解析で書いてみることにします。

src = "((((AAA,BBB),CCC),DDD),(EEE,FFF))"
p = 0

def node_p_():
    global p
    p += 1
    if src[p] == "(":
        e1 = node_p_()
    else:
        e1 = symbol_p_()
    p += 1
    if src[p] == "(":
        e2 = node_p_()
    else:
        e2 = symbol_p_()
    p += 1
    node =  (e1, e2)
    print(repr_node(node))
    return node

def symbol_p_():
    global p
    p += 3
    return src[p-3:p]

def repr_node(node):
    r = "("
    if isinstance(node[0], str):
        r += node[0]
    else:
        r += repr_node(node[0])
    r += ","
    if isinstance(node[1], str):
        r += node[1]
    else:
        r += repr_node(node[1])
    r += ")"
    return r

node_p_()
""" =>
(AAA,BBB)
((AAA,BBB),CCC)
(((AAA,BBB),CCC),DDD)
(EEE,FFF)
((((AAA,BBB),CCC),DDD),(EEE,FFF))
"""

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/27 18:38

    回答ありがとうございます。
    こういう問題を言葉になおしてくださって,助かりました。
    今後の勉強の参考にさせていただきます。

    キャンセル

0

内側から順に マッチ ⇒ 置換 することで実現できました。
かなり野暮ったい方法なのであまり達成感が無いですが...

import collections
import itertools
import re


src = r'((((AAA,BBB),CCC),DDD), (EEE,FFF))'

dst = []
work_dir = collections.OrderedDict()

for i in itertools.count():
    m = re.search(r'\([^()]+\)', src)
    if not m:
        break

    s = m.group()

    dst.append(s)
    work_dir[f'${i}'] = s
    src = src.replace(s, f'${i}')

for k, v in reversed(work_dir.items()):
    dst = [
        e.replace(k, v) for e in dst
    ]

print(*dst, sep='\n')

実行結果 Wandbox

(AAA,BBB)
((AAA,BBB),CCC)
(((AAA,BBB),CCC),DDD)
(EEE,FFF)
((((AAA,BBB),CCC),DDD), (EEE,FFF))

追記: 邪道

思い付いたので書きました。真似はしない方が良いです。

import ast
import re


src = r'((((AAA,BBB),CCC),DDD), (EEE,FFF))'
src = re.sub(r'(\w+)', r'"\1"', src)

work = [ast.literal_eval(src)]
dst = []

while work:
    tmp = work.pop()
    dst.append(tmp)

    work += [e for e in tmp if isinstance(e, tuple)]


dst = [
    str(e).replace('"', '').replace("'", "")
    for e in reversed(dst)
]
print(*dst, sep='\n')

実行結果 Wandbox

(AAA, BBB)
((AAA, BBB), CCC)
(((AAA, BBB), CCC), DDD)
(EEE, FFF)
((((AAA, BBB), CCC), DDD), (EEE, FFF))

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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