2014-02-12 3 views
-1

Мне было интересно, какую регулярную строку вы можете использовать для синтаксического анализа строки python. После нескольких не удается, я пришел к регулярному выражению-кода, который можно разобрать один из наиболее часто используемых форматов строк, какRegex version of python string

"this is \"my string\", which ends here" 

Это мой regex- «код»:

"([^"\\]|(\\.))*" 

Я задал этот вопрос потому что раньше я не нашел ничего подобного в Интернете. Могу ли я работать с этим выражением и «разрабатывать» его для анализа всех типов строк python? Если вы найдете этот вопрос интересным и I recommend you, где вы можете быстро проверить свои выражения.

+0

http://stackoverflow.com/questions/14366401/correctly-parsing-string-literals-with-pythons -re-module – thebjorn

+0

'r '" (?: \\ "| [^"]) * "'' –

+0

Не забывайте, что вам также нужно обрабатывать префиксы (unicode/raw string.) Например, u "ª unicode string ", r" \ У меня есть 3 буквальной обратной косой черты \\ ", UR'unícode и no \ e \ s \ c \ a \ p \ e characters. Также разделители - '/'/'' '/ "" ". И даже если вы не можете избежать разделителей в необработанной строке, вы все равно не можете покончить с необработанной строкой с обратным слэшем. Много крайних случаев, связанных с тем, что вы хотите. – GVH

ответ

2

Ваш шаблон регулярного выражения (и один в @thebjorn ссылки) потерпят неудачу, если есть нечетное число> 1 из обратных косой черты перед цитатой, я предлагаю вам использовать эту модель (с SingleLine режимом):

"(?:[^"\\]|\\{2}|\\.)*" 

оптимизированный способ:

"(?:(?=([^"\\]+|\\{2}|\\.))\1)*" 

, чтобы иметь дело с одинарными кавычками тоже:

(["'])(?:[^"'\\]|\\{2}|\\.|(?!\1)["'])*\1 

или

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

(обратите внимание, что последний символ из четырех моделей точно на той же строке, знак?)

2

Вот другой способ, который использует tokenize.generate_tokens для идентификации строк Python. Модуль tokenize использует regex; поэтому, используя tokenize, вы оставляете сложную грязную работу самому Python. Используя функции более высокого уровня, вы можете быть более уверенными в правильности регулярного выражения (и избегать повторного использования колеса). Более того, это будет правильно идентифицировать строки Python всех видов (например, строки одиночных кавычек, двойных кавычек и тройных цитируемых разновидностей), не путаясь комментариями.

import tokenize 
import token 
import io 
import collections 

class Token(collections.namedtuple('Token', 'num val start end line')): 
    @property 
    def name(self): 
     return token.tok_name[self.num] 

text = r'''foo = 1 "this is \"my string\", which ends here" bar''' 

for tok in tokenize.generate_tokens(io.BytesIO(text).readline): 
    tok = Token(*tok)   # 1 
    if tok.name == 'STRING':  # 2 
     print(tok.val) 
  1. tokenize.generate_tokens возвращает кортежи. Класс Token позволяет вам получить доступ к информации в кортеже.
  2. В частности, каждый токен имеет имя, например «STRING», «NEWLINE», «INDENT» или «OP». Вы можете использовать это, чтобы идентифицировать строки Python.

Edit: Мне нравится использовать класс маркеров, так что я не должен писать token.tok_name[num] во многих местах.Тем не менее, для приведенного выше кода, может быть яснее и проще забыть о классе маркеров и просто написать основную идею в явном виде:

import tokenize 
import token 
import io 

text = r'''foo = 1 "this is \"my string\", which ends here" bar''' 

for num, val, start, end, line in tokenize.generate_tokens(io.BytesIO(text).readline): 
    if token.tok_name[num] == 'STRING': 
     print(val) 
+0

Он выглядит очень техничным и превосходным, но действительно очень сложным, новым, как я. --- 'Токен (* tok)' вы говорите 'Класс Token позволяет вам получить доступ к информации в кортеже по-хорошему». Не ясно для меня. - Я добавил этот ответ для дальнейшего изучения. Спасибо, что добавил этот ответ. –

+0

Почему класс «токенов»? просто «Token = collections.namedtuple» («Token», «num val start end line») ', а затем' tok = Token._make (tok) 'будет делать ... (если я чего-то не хватает) –

+0

@JonClements: В более длинном коде мне не нравится писать 'token.tok_name [num]' повсюду. Замена этого атрибута 'name' является целью класса Token. – unutbu