1

Pythonでテキストの文字列を指定し、その内容をリストに分割し、3つのパラメーターで分割する方法が必要です-最も外側の括弧と最も外側の括弧と通常のテキスト、元の構文を維持します。

たとえば、与えられた文字列

(([a] b) c ) [d] (e) f

予想される出力は次のリストです。

['(([a] b) c )', '[d]', '(e)', ' f']

次のような正規表現でいくつかのことを試しました

\[.+?\]|\(.+?\)|[\w+ ?]+

私にくれた

>>> re.findall(r'\[.+?\]|\(.+?\)|[\w+ ?]+', '(([a] b) c ) [d] (e) f')
['(([a] b)', ' c ', ' ', '[d]', ' ', '(e)', ' f']

(間違ったリストの項目 c)

貪欲バージョンも試してみましたが、

\[.+\]|\(.+\)|[\w+ ?]+

しかし、文字列に同じ種類の個別の演算子がある場合は不十分です。

>>> re.findall(r'\[.+\]|\(.+\)|[\w+ ?]+', '(([a] b) c ) [d] (e) f')
['(([a] b) c ) [d] (e)', ' f']

次に、代わりにスタックを使用するように正規表現から移動しました。

>>> def parenthetic_contents(string):
    stack = []
    for i, c in enumerate(string):
        if c == '(' or c == '[':
            stack.append(i)
        elif (c == ')' or c == ']'):
            start = stack.pop()
            yield (len(stack), string[start + 0:i+1])

フラットテキストを取得する方法がないことを除いて、ブラケットと括弧の場合、どちらがうまく機能しましたか(または、取得できますが、それについてわかりませんか?):

>>> list(parenthetic_contents('(([a] b) c ) [d] (e) f'))
[(2, '[a]'), (1, '([a] b)'), (0, '(([a] b) c )'), (0, '[d]'), (0, '(e)')]

私はpyparsingに慣れていません。最初は、nestedExpr() でうまくいくように見えましたが、1 つの区切り文字 (() または [] で、両方ではない) しか必要としないため、うまくいきません。

私は今、すべてのアイデアがありません。どんな提案でも大歓迎です。

4

4 に答える 4

1

非常に軽くテストされただけです (出力には空白が含まれます)。@Mariusの回答(およびPDAを必要とする括弧の一致に関する一般的なルール)と同様に、スタックを使用します。ただし、私には少し余分なパラノイアが組み込まれています。

def paren_matcher(string, opens, closes):
    """Yield (in order) the parts of a string that are contained
    in matching parentheses.  That is, upon encounting an "open
    parenthesis" character (one in <opens>), we require a
    corresponding "close parenthesis" character (the corresponding
    one from <closes>) to close it.

    If there are embedded <open>s they increment the count and
    also require corresponding <close>s.  If an <open> is closed
    by the wrong <close>, we raise a ValueError.
    """
    stack = []
    if len(opens) != len(closes):
        raise TypeError("opens and closes must have the same length")
    # could make sure that no closes[i] is present in opens, but
    # won't bother here...

    result = []
    for char in string:
        # If it's an open parenthesis, push corresponding closer onto stack.
        pos = opens.find(char)
        if pos >= 0:
            if result and not stack: # yield accumulated pre-paren stuff
               yield ''.join(result)
               result = []
            result.append(char)
            stack.append(closes[pos])
            continue
        result.append(char)
        # If it's a close parenthesis, match it up.
        pos = closes.find(char)
        if pos >= 0:
            if not stack or stack[-1] != char:
                raise ValueError("unbalanced parentheses: %s" %
                    ''.join(result))
            stack.pop()
            if not stack: # final paren closed
                yield ''.join(result)
                result = []
    if stack:
        raise ValueError("unclosed parentheses: %s" % ''.join(result))
    if result:
        yield ''.join(result)

print list(paren_matcher('(([a] b) c ) [d] (e) f', '([', ')]'))
print list(paren_matcher('foo (bar (baz))', '(', ')'))
于 2013-07-05T00:43:46.563 に答える
1

level変数を使用してスタック内の深さを追跡する単純なパーサーを使用して、これを行うことができました。

import string

def get_string_items(s):
    in_object = False
    level = 0
    current_item = ''
    for char in s:
        if char in string.ascii_letters:
            current_item += char
            continue
        if not in_object:
            if char == ' ':
                continue
        if char in ('(', '['):
            in_object = True
            level += 1
        elif char in (')', ']'):
            level -= 1
        current_item += char
        if level == 0:
            yield current_item
            current_item = ''
            in_object = False
    yield current_item

出力:

list(get_string_items(s))
Out[4]: ['(([a] b) c )', '[d]', '(e)', 'f']
list(get_string_items('(hi | hello) world'))
Out[12]: ['(hi | hello)', 'world']
于 2013-07-05T00:13:45.170 に答える
0

ネストされた式の解析は深さ無制限で機能するという考えを捨てれば、事前に最大深さを指定することで正規表現を問題なく使用できます。方法は次のとおりです。

def nested_matcher (n):
    # poor man's matched paren scanning, gives up after n+1 levels.
    # Matches any string with balanced parens or brackets inside; add
    # the outer parens yourself if needed.  Nongreedy.  Does not
    # distinguish parens and brackets as that would cause the
    # expression to grow exponentially rather than linearly in size.
    return "[^][()]*?(?:[([]"*n+"[^][()]*?"+"[])][^][()]*?)*?"*n

import re

p = re.compile('[^][()]+|[([]' + nested_matcher(10) + '[])]')
print p.findall('(([a] b) c ) [d] (e) f')

これは出力されます

['(([a] b) c )', ' ', '[d]', ' ', '(e)', ' f']

これはあなたが上で述べたこととはまったく異なりますが、あなたの説明と例では、スペースで何をしようとしているのかを実際には明確にしませんでした.

于 2014-04-02T17:48:30.570 に答える