私はこのような文字列を持っています:
これは[ブラケットテスト]"と引用符テスト"です
中括弧と引用符内のスペースを無視して、Pythonで何かをスペースで分割するように作成しようとしています。私が探している結果は次のとおりです。
['this'、'is'、'bracket test'、'and quotes test']
テスト入力で機能する単純なソリューションを次に示します。
import re
re.findall('\[[^\]]*\]|\"[^\"]*\"|\S+',s)
これにより、いずれかに一致するコードが返されます
これはあなたの例では機能しますが、実際に遭遇する可能性のある多くの文字列では失敗する可能性があります。たとえば、アンバランスな括弧や引用符で何を期待するか、単一引用符やエスケープ文字をどのように機能させたいかを言いませんでした。ただし、単純なケースでは、上記で十分な場合があります。
ブライアンの投稿を完成させ、答えを正確に一致させるには:
>>> import re
>>> txt = 'this is [bracket test] "and quotes test "'
>>> [x[1:-1] if x[0] in '["' else x for x in re.findall('\[[^\]]*\]|\"[^\"]*\"|\S+', txt)]
['this', 'is', 'bracket test', 'and quotes test ']
使用されている構文全体を誤解しないでください。これは、1 行に複数のステートメントがあるのではなく、1 つの関数ステートメントです (よりバグ防止)。
State 設計パターンを導入する単純なパーサー (入力例に対してテスト済み) を次に示します。
現実の世界では、おそらくPLYのようなものを使用して実際のパーサーを構築したいと思うでしょう。
class SimpleParser(object):
def __init__(self):
self.mode = None
self.result = None
def parse(self, text):
self.initial_mode()
self.result = []
for word in text.split(' '):
self.mode.handle_word(word)
return self.result
def initial_mode(self):
self.mode = InitialMode(self)
def bracket_mode(self):
self.mode = BracketMode(self)
def quote_mode(self):
self.mode = QuoteMode(self)
class InitialMode(object):
def __init__(self, parser):
self.parser = parser
def handle_word(self, word):
if word.startswith('['):
self.parser.bracket_mode()
self.parser.mode.handle_word(word[1:])
elif word.startswith('"'):
self.parser.quote_mode()
self.parser.mode.handle_word(word[1:])
else:
self.parser.result.append(word)
class BlockMode(object):
end_marker = None
def __init__(self, parser):
self.parser = parser
self.result = []
def handle_word(self, word):
if word.endswith(self.end_marker):
self.result.append(word[:-1])
self.parser.result.append(' '.join(self.result))
self.parser.initial_mode()
else:
self.result.append(word)
class BracketMode(BlockMode):
end_marker = ']'
class QuoteMode(BlockMode):
end_marker = '"'
より手続き的なアプローチは次のとおりです。
#!/usr/bin/env python
a = 'this is [bracket test] "and quotes test "'
words = a.split()
wordlist = []
while True:
try:
word = words.pop(0)
except IndexError:
break
if word[0] in '"[':
buildlist = [word[1:]]
while True:
try:
word = words.pop(0)
except IndexError:
break
if word[-1] in '"]':
buildlist.append(word[:-1])
break
buildlist.append(word)
wordlist.append(' '.join(buildlist))
else:
wordlist.append(word)
print wordlist
さて、私はこの問題に何度も遭遇したため、あらゆる種類の構文を解析するための独自のシステムを作成することになりました。
この結果はここにあります。これはやり過ぎかもしれないことに注意してください。これにより、ブラケットと括弧の両方、一重引用符と二重引用符を必要に応じてネストしてステートメントを解析できるようになります。たとえば、次のようなものを解析できます (Common Lisp で書かれた例):
(defun hello_world (&optional (text "Hello, World!"))
(format t text))
ネスト、括弧 (四角) と括弧 (丸)、一重引用符と二重引用符で囲まれた文字列を使用でき、非常に拡張性があります。
このアイデアは基本的に、文字ごとに抽象的な構文ツリーを構築する有限状態マシンの構成可能な実装です。ソース コード (上記のリンクを参照) を参照して、その方法を理解することをお勧めします。正規表現を介して可能ですが、RE を使用してシステムを作成し、後でそれを拡張する (または理解する) ことを試みてください。
見積もりのみで機能します。
rrr = []
qqq = s.split('\"')
[ rrr.extend( qqq[x].split(), [ qqq[x] ] )[ x%2]) for x in range( len( qqq ) )]
print rrr