일부 텍스트를 분할하려고합니다. 기본적으로 나는 "('1','a',NULL),(2,'b')"
=>["('1','a',NULL)", "(2,'b')]"
과 같이 1 단계 괄호를 분리하고 싶지만 내부에 가능한 인용 문자열을 알아야합니다. 나는 다음과 같은 시도따옴표 붙은 문자열을 포함 할 수있는 꺾쇠 괄호로 구분 된 텍스트
from splitter import split_text
def test_normal():
assert split_text("('1'),('2')") == ["('1')", "('2')"]
assert split_text("(1),(2),(3)") == ["(1)", "(2)", "(3)"]
def test_complex():
assert split_text("('1','a'),('2','b')") == ["('1','a')", "('2','b')"]
assert split_text("('1','a',NULL),(2,'b')") == ["('1','a',NULL)", "(2,'b')"]
def test_apostrophe():
assert split_text("('\\'1','a'),('2','b')") == ["('\\'1','a')", "('2','b')"]
def test_coma_in_string():
assert split_text("('1','a,c'),('2','b')") == ["('1','a,c')", "('2','b')"]
def test_bracket_in_string():
assert split_text("('1','a)c'),('2','b')") == ["('1','a)c')", "('2','b')"]
def test_bracket_and_coma_in_string():
assert split_text("('1','a),(c'),('2','b')") == ["('1','a),(c')", "('2','b')"]
def test_bracket_and_coma_in_string_apostrophe():
assert split_text("('1','a\\'),(c'),('2','b')") == ["('1','a\\'),(c')", "('2','b')"]
: 그것은 최소한 다음 py.tests 만족해야
1) 정규 표현식이 최선의 해결책처럼 보이는
,하지만 불행하게도 내가 그랬어 모든 검사를 만족시키는 것은 없습니다.
def split_text(text):
return re.split('(?<=\)),(?=\()', text)
그러나 분명히, 즉 오히려 단순하고 test_bracket_and_coma_in_string
및 test_bracket_and_coma_in_string_apostrophe
실패 :
내 최고의 시도이다.
2) 유한 상태 기계와 같은 솔루션
은 내가 FSM 자신을 코딩하는 시도 :
그것은 작동OUTSIDE, IN_BRACKETS, IN_STRING, AFTER_BACKSLASH = range(4)
def split_text(text):
state = OUTSIDE
read = []
result = []
for character in text:
if state == OUTSIDE:
if character == ',':
result.append(''.join(read))
read = []
elif character == '(':
read.append(character)
state = IN_BRACKETS
else:
read.append(character)
elif state == IN_BRACKETS:
read.append(character)
if character == ')':
state = OUTSIDE
elif character == "'":
state = IN_STRING
elif state == IN_STRING:
read.append(character)
if character == "'":
state = IN_BRACKETS
elif character == '\\':
state = AFTER_BACKSLASH
elif state == AFTER_BACKSLASH:
read.append(character)
state = IN_STRING
result.append(''.join(read)) # The rest of string
return result
이 모든 테스트를 통과,하지만 매우 느린 입니다.
from pyparsing import QuotedString, ZeroOrMore, Literal, Group, Suppress, Word, nums
null_value = Literal('NULL')
number_value = Word(nums)
string_value = QuotedString("'", escChar='\\', unquoteResults=False)
value = null_value | number_value | string_value
one_bracket = Group(Literal('(') + value + ZeroOrMore(Literal(',') + value) + Literal(')'))
all_brackets = one_bracket + ZeroOrMore(Suppress(',') + one_bracket)
def split_text(text):
parse_result = all_brackets.parseString(text)
return [''.join(a) for a in parse_result]
대한 파싱을
3)의 모든 테스트를 통과하지만, 놀랍게도 용액 # 2보다 느릴이다.
솔루션을 빠르고 강력하게 만드는 방법에 대한 아이디어가 있으십니까? 나는 명백한 무언가를 놓치고 있다는 느낌을 가지고있다.
솔루션 # 2 및 # 3보다 빠르다고 생각하십니까? – Fenikso
그래서 IMHO는 FSM이며 실제 데이터의 속도는 솔루션 # 2와 비슷합니다. – Fenikso
해결책은 각 문자열에 대해 O (n)입니다. 여기서 n은 문자열의 길이입니다. 그래서, 적어도 한 번 이상 문자열을 스캔해야하기 때문에 얻을 수있는 가장 빠른 속도입니다. – Rahul