Использование python для разделения строки с разделителем, игнорируя разделитель и экранирование кавычек внутри кавычек - PullRequest
2 голосов
/ 01 марта 2011

Я пытаюсь разбить строку в зависимости от расположения разделителя (я пытаюсь удалить комментарии из кода Фортрана).Я могу разделить, используя ! в следующей строке:

x = '''print "hi!" ! Remove me'''
pattern = '''(?:[^!"]|"[^"]*")+'''
y = re.search(pattern, x)

Однако это не удастся, если строка содержит escape-кавычки, например

z = '''print "h\"i!" ! Remove me'''

Можно ли изменить регулярное выражение для обработки escapeцитаты?Или я даже не должен использовать регулярные выражения для такого рода проблем?

Ответы [ 3 ]

3 голосов
/ 01 марта 2011

Вот проверенное регулярное выражение (из Освоение регулярных выражений ) для сопоставления строковых литералов в двойных кавычках, которые могут содержать кавычки с обратной косой чертой:

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

В кавычках с разделителями он потребляет любую пару символов, которая начинается с обратной косой черты, не удосуживаясь идентифицировать второй символ; это позволяет ему обрабатывать экранированные обратные слэши и другие escape-последовательности без лишних хлопот. Это также эффективно, как и при отсутствии собственнических квантификаторов и атомных групп , которые не поддерживаются Python.

Полное регулярное выражение для вашего приложения будет:

r'^((?:[^!"]+|"[^"\\]*(?:\\.[^"\\]*)*")*)!.*$'

Это соответствует только строкам, содержащим комментарии, и захватывает все, что предшествовало комментарию в группе # 1. Захват может быть нулевой длины для строк, которые начинаются с !. Это регулярное выражение предназначено для использования с sub вместо search, как показано здесь:

import re

pattern = r'^((?:[^!"]+|"[^"\\]*(?:\\.[^"\\]*)*")*)!.*$'

x = '''print "hi!" ! Remove me'''
y = re.sub(pattern, r'\1', x)
print(y)

Посмотрите это в действии на ideone.com

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Этот ответ не о ФОРТРАНЕ, а только о коде, который следует правилам, указанным в вопросе. Я никогда не работал с FORTRAN, и каждая ссылка, которую я нашел за последний час или около того, кажется, описывает совершенно другой язык. Мех!

2 голосов
/ 01 марта 2011

Разбор Фортрана на самом деле довольно сложен (см., Например, нить здесь ).Я блаженно незнаком с деталями синтаксиса и где '!'может произойти.Поэтому возникает мысль: насколько вероятно, что в самих комментариях есть «!»?Если это маловероятно, вы можете просто удалить все после последнего '!'в каждой строке:

def cleanup(line):
  splitlist = line.split("!")
  if len(splitlist) > 1 and "\"" not in splitlist[-1]:
      return '!'.join(splitlist[:-1]).strip()
  else:
      return line

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

Редактировать:

Похоже, NumPy включает в себя синтаксический анализатор Fortran на основе Python в пакете F2py .В зависимости от лицензионных ограничений вы можете переработать этот код для надежного анализа «кода, но не комментариев».

2 голосов
/ 01 марта 2011

Что вам нужно, так это отрицательный взгляд за утверждением: (?<!...).

Например:

z = r'''print "h\"i!" ! Remove me'''
pattern = r'''(?:[^!"]|(?<!\\)".*(?<!\\)")+'''
y = re.search(pattern, z)

print(y.group(0))


Выход:

print "h\"i!" 



Как указано в комментариях, вышеприведенное выражение не будет обрабатывать экранированные обратные слэши. Также он не будет обрабатывать одинарные кавычки, которые разрешены в FORTRAN. Это должно работать и для тех случаев (я думаю):

 pattern = r'''(?:[^!"']|((?<!\\)"|(\\\\)+").*?((?<!\\)"|(\\\\)+")|((?<!\\)'|(\\\\)+').*?((?<!\\)"|(\\\\)+'))+'''

Это немного уродливо. , .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...