python 文字列分割 - ぶやかー

splitやre.splitよりshelex.split使うとよい場合が多い

shelex.splitはデフォルトでPOSIXモードで動作するので引用符(‘)、二重引用符(“)で囲まれた文字列をいい感じに判断してくれる。
ちなみに、shlex.splitはデフォルトでは空白文字(\s. \t. \r, \n, \r\n)をdelimita(区切り文字)と判定している。と思う

>>> import re, shlex, textwrap
>>> from rich import pretty, print
>>> pretty.install()
>>>
>>> test_orig_text = textwrap.dedent('''\
... 1.0.0.1     None    None    None
... 8.8.4.4     None    None    None
... 198.51.100.0        None    None    None
... a b c d
... a  b  this is a this
... s m sm "hoge hoge"
... a,b,c,d
... ''')
>>>
>>> test_re_text = []
>>> test_shlex_text = []
>>>
>>> for l in test_orig_text.splitlines():
...     test_re_text.append(re.findall(r'\S+', l))
...     test_shlex_text.append(shlex.split(l))
...
>>> print(test_re_text)
[
    ['1.0.0.1', 'None', 'None', 'None'],
    ['8.8.4.4', 'None', 'None', 'None'],
    ['198.51.100.0', 'None', 'None', 'None'],
    ['a', 'b', 'c', 'd'],
    ['a', 'b', 'this', 'is', 'a', 'this'],
    ['s', 'm', 'sm', '"hoge', 'hoge"'],
    ['a,b,c,d']
]
>>> print(test_shlex_text)
[
    ['1.0.0.1', 'None', 'None', 'None'],
    ['8.8.4.4', 'None', 'None', 'None'],
    ['198.51.100.0', 'None', 'None', 'None'],
    ['a', 'b', 'c', 'd'],
    ['a', 'b', 'this', 'is', 'a', 'this'],
    ['s', 'm', 'sm', 'hoge hoge'],
    ['a,b,c,d']
]
>>>
>>> print(shlex.split(test_orig_text))
['1.0.0.1', 'None', 'None', 'None', '8.8.4.4', 'None', 'None', 'None', '198.51.100.0', 'None', 'None', 'None', 'a', 'b', 'c', 'd', 'a', 'b', 'this', 'is', 'a', 'this', 's', 'm', 'sm', 'hoge hoge', 'a,b,c,d']
>>>

shelexでカンマ区切りしたい場合。
余分なスペースもいい感じに排除してくれる。

>>> import shlex, textwrap
>>> 
>>> test_orig_text = textwrap.dedent('''\
... 1.0.0.1     None    None    None
... 8.8.4.4     None    None    None
... 198.51.100.0        None    None    None
... a b c d
... a  b  this is a this
... s m sm "hoge hoge"
... a,b,c,d
... a , b, c ,    d
... ''')
>>>
>>>
>>> test_shlex_shlex = shlex.shlex(test_orig_text)
>>> test_shlex_shlex.whitespace += ','
>>> test_shlex_shlex.whitespace_split = True
>>> print(list(test_shlex_shlex))
['1.0.0.1', 'None', 'None', 'None', '8.8.4.4', 'None', 'None', 'None', '198.51.100.0', 'None', 'None', 'None', 'a', 'b', 'c', 'd', 'a', 'b', 'this', 'is', 'a', 'this', 's', 'm', 'sm', '"hoge hoge"', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']
>>>

さらにちなみに、正規表現の変態になるとこんなことになるらしい。(カンマ区切りの例だけど)

>>> import re
>>> pattern = re.compile(r'\s*("[^"]*"|.*?)\s*,')
>>> def split(line):
...  return [x[1:-1] if x[:1] == x[-1:] == '"' else x
...          for x in pattern.findall(line.rstrip(',') + ',')]
... 
>>> split("foo, bar, baz")
['foo', 'bar', 'baz']
>>> split('foo, bar, baz, "blub blah"')
['foo', 'bar', 'baz', 'blub blah']

この記事を書いた人 Wrote this article

kmatsunuma

TOP