40411

[code]

    sample = "アイス{}{}ー"
    
[/code]

という文があるとします。  
この中の `{}` を、分割をす‌​るパワーを持つもの、デ‌​ィヴィジョナー・分割者（独自用語です）と考えます。  
（デリミタというのは辞書で調べると、データの区切りにつけるマークということで、‌​たとえば、この場合だと、コンマ(`,`)だと‌​考えました。なので、分割をす‌​るパワーを持つものを、`{}`として、デ‌​ィヴィジョナーとしたつもりです）

[code]

    sample.split("{}")
    
[/code]

とすると、  
通常の結果は、

[code]

    ["アイス","","ー"]
    
[/code]

となります。  
これを、

[code]

    ["アイス","","","ー"]
    
[/code]

と出力する方法はありますか？


CC BY-SA 3.0
2017-12-20T01:11:50.097
40401
2017-12-20T10:03:09.987
2017-12-20T08:57:02.817
3054
24284
question
python
{} を含む文字列を {} の前後でリストに分割し、{} 自体は空文字とする方法


逆方向に考えてみましょう。データが複数個あって、それを表現する方法として「デリミタで区切った文字列」を生成するのだと考えてみてください。

"A","B","C","D"という四つのデータがあって、それをデリミタを","で文字列化すると"A,B,C,D"という文字列になります。そこでデリミタを"{}"にする、と規定した場合、文字列は"A{}B{}C{}D"になります。逆方向の変換ではプログラムは"{}"に遭遇したらその前後を切り出すという処理をしますので、この文字列をデリミタ"{}"で区切れば"A","B","C","D"というデータを取り出すことができますよね。

しかし、Haruさんがやりたいことの一つは"{}"が出現したら空文字列として切り出してほしい、だと思います。ですが、これだけだと、空文字列ではないデータを区切ることができません。

もう一度"{}a{}"について考えてみましょう。これは"","a",""に切り出せます、つまり、Haruさんの想定しているルールで、データ"","a",""を表現すれば、"{}a{}"となります。

しかし、"","a","b",""というデータをその表現形式に落とし込むことはできません。なぜなら、"a"と"b"の境界を表現する方法がないからです。これを文字列化するなら"{}a（何か"{}"ではない別の区切り文字）b{}"になります。必ず「何か"{}"ではない別の区切り文字」が必要になります。そしてそれこそが本来の「デリミタ」です。

例えば、「デリミタは","、ただし、空文字列は{}で表現し、空文字列と空ではないデータの区切りでは","を省略してもよい」というようなルールを決めれば（そんなルールを採用することがあるかどうかは別として）、"","a","b",""は"{}a,b{}"という文字列にできます。

あるいは、元々のデータ自体が空文字列同士が連続することはあっても、空文字列ではないデータが連続することはないのかも知れません。そうであれば、"","a","b",""というデータ自体が不正なので、これをどのような文字列に落とし込むかを悩む必要はありません。その場合はデリミタという概念は捨てて、「データを連続で文字列化する、ただし空文字列は"{}"で表わす」というルールを定めればいいのです。こうするとデリミタがそもそも不要になります。（そんなデータを出力するシステムがあるかどうかは別として。）


CC BY-SA 3.0
2017-12-20T03:34:21.247
40407
2017-12-20T03:42:16.230
2017-12-20T03:42:16.230
5734
5734
40401
answer


`{}` が空文字を生成するということは、`{` と `}`
は、文字列を囲むための構文であると考えられます（こういった構文の一部は、文脈によって、クォートと呼ばれることがあります）。  
以下はそれを前提とします。  
つまり、`{abc}` は `abc` になります。

### 正規表現

正規表現だと、例えばこのような表現が考えられます。

[code]

    #!/usr/bin/python3
    import re
    quoted = "アイス{}{}ー"
    
    words = re.findall("[^{}]+|(?<={)[^{}]*(?=})", quoted)
    print(words)
    
[/code]

出力:

[code]

    ['アイス', '', '', 'ー']
    
[/code]

[`re.X`フラグ](https://docs.python.jp/3/library/re.html#re.X)で説明を付けたのが以下です。

[code]

    words = re.findall(
        """
            # 囲われていない部分
            [^{}]+
        |
            # { } で囲われている部分
                # { は結果に含めない
                (?<={)
                    # 中身
                    [^{}]*
                # } は結果に含めない
                (?=})
        """,
        quoted,
        flags=re.X
    )
    
[/code]

### 正規表現の補助的な使用

将来のことを考えると、正規表現の使用は控えめにするべきです。

[code]

    words = re.findall("[^ {} ]+  |  [ {} ]", quoted, flags=re.X)
    print("words:", words)
    
    prev = None
    result = []
    for w in words:
        if w not in "{}":
            result.append(w)
        elif prev == "{" and w == "}":
            result.append("")
        prev = w
    print("result:", result)
    
[/code]

出力:

[code]

    words: ['アイス', '{', '}', '{', '}', 'ー']
    result: ['アイス', '', '', 'ー']
    
[/code]


CC BY-SA 3.0
2017-12-20T05:13:00.290
40411
2017-12-20T08:58:35.513
2017-12-20T08:58:35.513
3054
3054
40401
answer


こうでしょうか

[code]

    >>> import re
    >>> sample = "アイス{}{}ー"
    >>> re.split('{}', sample)
    ['アイス', '', 'ー']
    
    >>> re.split('({})', sample)
    ['アイス', '{}', '', '{}', 'ー']
    
    >>> [s for s in re.split('({})', sample) if s]
    ['アイス', '{}', '{}', 'ー']
    
    >>> delimiter = "{}"
    >>> [s for s in re.split('(%s)' % delimiter, sample) if s]
    ['アイス', '{}', '{}', 'ー']
    
    >>> [
    ...     s if s != delimiter else ''
    ...     for s in re.split('(%s)' % delimiter, sample)
    ...     if s
    ... ]
    ['アイス', '', '', 'ー']
    
    >>> [s if s != delimiter else '' for s in re.split('(%s)' % delimiter, '{}a{}') if s]
    ['', 'a', '']
    
    >>> [s if s != delimiter else '' for s in re.split('(%s)' % delimiter, 'b{}c') if s]
    ['b', '', 'c']
    
[/code]


CC BY-SA 3.0
2017-12-20T05:13:37.127
40412
2017-12-20T05:13:37.127
806
40401
answer


せっかくなので。

冒頭と末尾に`{}`が来ないことが保証できるなら `{}` を一つ増やしてsplitすることに等しいですよね。  
一つ **足りないと思っている** のですから、一つ **増やせばいい** と考えるのは自然ではないでしょうか。

[code]

    >>> import re
    >>> sample = "アイス{}{}ー"
    >>> re.sub('(\{\})+', lambda m: '{}' * (len(m.group(0)) // 2 + 1), sample).split('{}')
    ['アイス', '', '', 'ー']
    
[/code]

冒頭と末尾に`{}`にくる時の挙動が望み通りではないでしょうから、あとから削除すればいいかと。

[code]

    >>> l = re.sub('(\{\})+', lambda m: '{}' * (len(m.group(0)) // 2 + 1), "{}a{}").split('{}')
    >>> if l[0] == '':
    ...     l = l[1:]
    ...
    >>> if l[-1] == '':
    ...     l = l[:-1]
    ...
    >>> l
    ['', 'a', '']
    
[/code]


CC BY-SA 3.0
2017-12-20T10:03:09.987
40424
2017-12-20T10:03:09.987
12274
40401
answer