2014-01-31 5 views
2

Я разбираю исходный код Python, и у меня есть регулярные выражения для одиночных и двойных кавычек (полученные путем чтения ответа ridgerunner на this thread).Regex для сопоставления многострочной строки Python с экранированными символами

single_quote_re = "'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'"; 

double_quote_re = '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"'; 

Я пытаюсь обрабатывать многострочные строки Python сейчас (три двойных кавычки).

s = '"""string one\'s end isn\'t here; \\""" it\'s here """ """string two here"""' 
# correct output for findall should be: 
#  ['string one\'s end isn\'t here; \\""" it\'s here ','string two here'] 

Я попытался немного пообщаться с ним, но все же это неправильно.

multiline_string_re = '"""([^(""")\\\\]*(?:\\\\.[^(""")\\\\]*)*)"""' 

Там же должен быть какой-то способ сказать «»», что сразу не предшествует обратный слэш (другими словами, первые двойные кавычки не убежали)

EDIT:. Я должен быть ближе, я попытался следующие:

r'(?<!\\)""".*(?<!\\)"""' 
# Matches the entire string; not what I'm going for. 

r'(?<!\\)"""[^((?<!\\)""")](?<!\\)"""' 
# Matches that space between the two strings ('""" """') in the sample string s (see code above, prior to edit). 

r'(?<!\\)"""([^((?<!\\)""")]*(?:\\.[^((?<!\\)""")]*)*)(?<!\\)"""' 
# Same result as before, but with the triple quotes shaved off (' '). 
# Note: I do indeed want the triple quotes excluded. 

UPDATE: решение, благодаря SLn, по-видимому, "" "[^" \\] (:(? : \\ | "") [^ "\\]) *" ""

multiline_string_re = '"""[^"\\\\]*(?:(?:\\\\.|"")[^"\\\\]*)*"""' 
re.findall(multiline_string_re, s, re.DOTALL) 
# Result: 
# ['"""string one\'s end isn\'t here; \\""" it\'s here """', '"""string two here"""'] 

Обновленное решение, еще раз спасибо SLn:.

multiline_single_re = "'''[^'\\\\]*(?:(?:\\\\.|'{1,2}(?!'))[^'\\\\]*)*'''" 
multiline_double_re = '"""[^"\\\\]*(?:(?:\\\\.|"{1,2}(?!"))[^"\\\\]*)*"""' 
+1

' "" ", которому не сразу предшествует обратная косая черта ':' (? tenub

+0

Если его сеть Vebatim ala Dot @ "", то нет escape char \\. То есть. '" string \\ "' -> '@" "" string \\ "" "'. Это так, как в Dot-net. Разница в питоне? – sln

+0

@sln: AFAIK, дословный формат с python выглядит так: 'r '....'' –

ответ

1

Вот тестовый пример с использованием регулярного выражения в Perl. Если вы собираетесь разрешить побег
все, что угодно, а также экранированную форму двойной кавычки "", просто измените один из
regex, который вы указали, чтобы разрешить двойную двойную кавычку.

Исходная строка удаляется из одиночной кавычки.

use strict; 
use warnings; 

$/ = undef; 

my $str = <DATA>; 

while ($str =~ /"[^"\\]*(?:(?:\\.|"")[^"\\]*)*"/sg) 
{ 
    print "found $&\n"; 

} 

    __DATA__ 

    """string one's end isn't here; \""" it's here """ """string two here""" 

Выход >>

found """string one's end isn't here; \""" it's here """ 
found """string two here""" 

Обратите внимание, что для действия и ошибки обработки, регулярное выражение необходимо будет содержать
Сквозная конструкции (переменного тока), которые могут быть обработаны в теле время петля.
Пример /"[^"\\]*(?:(?:\\.|"")[^"\\]*)*"|(.)/sg,
затем
в то время как() {
// если соответствует группе 1, и его не пробельные = возможная ошибка
}

Добавить - В ответ на комментарии.

После некоторых исследований на блоке питона literals,

кажется, вы должны обрабатывать не только экранированные символы, но
до 2 двойных кавычек в теле. То есть. " или ""

Изменить регулярное выражение просто. Добавьте квантор 1-2 и сдерживайте его взглядом.

Ниже представлены необработанные и строковые элементы регулярного выражения, которые вы можете выбрать.
Протестировано в Perl, оно работает.
Удачи!

# Raw - 
# (?s: 
# """[^"\\]*(?:(?:\\.|"{1,2}(?!"))[^"\\]*)*""" 
# | 
# '''[^'\\]*(?:(?:\\.|'{1,2}(?!'))[^'\\]*)*''' 
# ) 
# String'd - 
# '(?s:' 
# '"""[^"\\\]*(?:(?:\\\.|"{1,2}(?!"))[^"\\\]*)*"""' 
# '|' 
# "'''[^'\\\\]*(?:(?:\\\\.|'{1,2}(?!'))[^'\\\\]*)*'''" 
# ')' 


(?s:    # Dot-All 
     # double quote literal block 
     """     # """ block open 
     [^"\\]*    # 0 - many non " nor \ 
     (?:     # Grp start 
      (?: 
       \\ .    # Escape anything 
      |      # or 
       "{1,2}    # 1 - 2 " 
       (?! ")    # Not followed by a " 
      ) 
      [^"\\]*    # 0 - many non " nor \ 
    )*     # Grp end, 0 - many times 
     """     # """ block close 

    |      # OR, 

     # single quote literal block 
     '''     # ''' block open 
     [^'\\]*    # 0 - many non ' nor \ 
     (?:     # Grp start 
      (?: 
       \\ .    # Escape anything 
      |      # or 
       '{1,2}    # 1 - 2 ' 
       (?! ')    # Not followed by a ' 
      ) 
      [^'\\]*    # 0 - many non ' nor \ 
    )*     # Grp end, 0 - many times 
     '''     # ''' block close 
) 
+0

Протестировано в Python, и пока это похоже на трюк. Большое спасибо! Для справки для тех, кто хочет использовать это регулярное выражение в Python, это «[^» \\\\] * (?: (?: \\\\. | "") [^ "\\\\] *) *" (начало и конец кавычек являются частью выражения). –

+0

Обновление: для этого требуется небольшая модификация: "" "[^" \\\\] * (?: (?: \\\\. | "") [^ "\\\\] *) *" "". Как бы то ни было, он также соответствовал простым строкам с двойными кавычками, а не многострочной версией. –

+0

@Brad T - Я добавил модифицированное регулярное выражение в свой пост. Я думаю, вы должны учитывать 1 или 2 кавычки в теле буквального блока. В противном случае '' "" это "quote", end "" "' не будет передавать старое регулярное выражение. Модифицированный исправляет это. – sln

1

Этот фрагмент кода должен сопоставляйте три кавычки, которые перед ними имеют только обратную косую черту.

[^\\]""" 

Вы можете интегрировать это в свое регулярное выражение.

1

Вы не можете разобрать исходный код Python с помощью «простых» регулярных выражений.

Хорошей новостью является то, что стандартная библиотека Python поставляется с полноценным парсером Python в виде модуля ast (http://docs.python.org/2/library/ast.html). Используйте это вместо этого.

В частности, функция literal_eval будет анализировать литералы (включая все типы строк и следующие правила экранирования), а функция parse будет анализировать произвольный исходный код Python в абстрактное синтаксическое дерево.

Кроме того, следует иметь в виду, что ваш пример (ы) на самом деле разбирает в один строку: 'string one\'s end isn\'t here; """ it\'s here string two here', потому что в Python, смежные строковые литералы сцепляются в синтаксическое время, например, так:

>>> "a" "b" "c" 
"abc" 
+0

Единственная проблема с этим в моем случае состоит в том, что модуль парсера, который я создаю, предназначен для работы со многими языками программирования (например, Java, CSS, HTML, JavaScript и т. Д.). Это не чистое регулярное решение. С этим умом я пытаюсь решить такие проблемы, как этот, с помощью регулярных выражений и/или логики программирования. Дело в том, чтобы разбить каждый компонент синтаксиса в целевом исходном коде, чтобы я мог идентифицировать и работать с каждым программным способом. К сожалению, модуль ast - это Python. –

+1

В этом случае то, что вы пишете, называется парсером, это не простая коллекция регулярных выражений, и это, конечно, не язык-агностик: языки, о которых вы упомянули, имеют очень разные грамматики (Python's in in 'ast' docs, btw). В зависимости от того, что вы хотите сделать, существует множество существующих библиотек, которые вы хотите использовать, вместо того, чтобы развертывать свои собственные: если все, что вы ищете, - это подсветка синтаксиса, Pygments (http://pygments.org/) для более чем ста языков. Если вы хотите провести более общий анализ, взгляните на Parsley (http://parsley.readthedocs.org/en/latest/). –

+0

Глядя на документацию, Петрушка именно то, что мне нужно для моего проекта в целом. Большое спасибо, мужик. Это определенно спасет мне огромное количество головных болей и работы. –

Смежные вопросы