Разбор строки с некоторыми определенными ключевыми словами для разделения (вне строковых литералов), но не разделенных внутри строковых литералов в Python

могу ли я задать вопрос о проблеме, с которой я столкнулся в эти дни? Буду очень признателен, если вы, ребята, поможете мне решить эту проблему :)

Итак, у меня есть эта простая строка, которую я хочу разобрать, используя ключевое слово '@' (анализируйте это только в том случае, если '@' находится вне строки, которая находится внутри строки). Причина этого в том, что я пытаюсь научиться анализировать некоторые строки на основе определенных ключевых слов для анализа/разделения, потому что я пытаюсь реализовать свой собственный "простой язык программирования"...

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

# Ignore the 'println(' thing, it's basically a builtin print statement that I made, so
# you can only focus on the string itself :)

# (?!\B"[^"]*)@(?![^"]*"\B)
# As I looking up how to use this thing with regex, I found this one that basically
# split the strings into elements by '@' keyword, but not splitting it if '@' is found
# inside a string. Here's what I mean:

# '"[email protected]"'     --- found '@' inside a string, so don't parse it
# '"[email protected]" @ x' --- found '@' outside a string, so after being parsed would be like this:
# ['"[email protected]", x']
print_args = re.split(r'(?!\B"[^"]*)@(?![^"]*"\B)', codes[x].split('println(')[-1].removesuffix(')\n' or ')'))
vars: list[str] = []
result_for_testing: list[str] = []
            
for arg in range(0, len(print_args)):
    # I don't know if this works because it's split the string for each space, but
    # if there are some spaces inside a string, it would be considered as the spaces
    # that should've been split, but it should not be going to be split because
    # because that space is inside a string that is inside a string, not outside a
    # string that is inside a string.

    # Example 1: '"Hello, World!" @   x @     y' => ['"Hello, World!"', x, y]
    # Example 2: '"Hello,      World!      " @    x @   y' => ['"Hello,      World!      "', x, y]
    # At this point, the parsing doesn't have to worry about unnecessary spaces inside a string, just like the example 2 is...
    compare: list[str] = print_args[arg].split()

    # This one is basically checking if '"'is not in a string that has been parsed (in this
    # case is a word that doesn't have '"'). Else, append the whole thing for the rest of
    # the comparison elements
    
    # Here's the string: '"Value of a is: " @ a @ "String"' [for example 1]
    # Example 1: ['"Value of a is: "', 'a', '"String"'] (This one is correct)

    # Here's the string: '"   Value of a is: " @ a @ "   String"'
    # Example 2: ['" Value of a is: " @ a @ " String"'] (This one is incorrect)
    vars.append(compare[0]) if '"' not in compare[0] else vars.append(" ".join(compare[0:]))
    
    for v in range(0, len(vars)):
        # This thing is just doing it job, appending the same elements in 'vars'
        # to the 'result_for_testing'
        result_for_testing.append(vars[v])

print(result_for_testing)

После таких операций вывод, который я получаю для анализа основных вещей без лишних пробелов, выглядит следующим образом:

string_to_be_parsed: str = '"Value of a is: " @ a @ "String"'
Output > ['"Value of a is: "', 'a', '"String"'] # As what I'm expected to be...

Но как-то ломается, когда что-то вроде этого (с ненужными пробелами):

string_to_be_parsed: str = '"   Value    of  a  is:     "    @     a   @  "   String  "'
Output > ['" Value of a is: " @ a @ " String "']
# Incorrect result and I'm hoping the result will be like this:

Expected Output > ["   Value    of  a  is:     ", a, "   String  "]
# If there are spaces inside a string, it just has to be ignored, but I don't know how to do it

Хорошо, ребята, это проблемы, с которыми я столкнулся, и вывод:

  1. Как разобрать строку и разбить каждую строку внутри строки по ключевому слову «@», но не будет разбиваться, если «@» находится внутри строки в строке?
Example: '"@ in a string inside a string" @ is_out_from_a_string'
The result should be: ['"@ in a string inside a string"', is_out_from_a_string]
  1. При разборе строк, как игнорировать все пробелы внутри строки в строке?
Example: '"    unnecessary      spaces  here      too" @ x @ y @ z "   this   one     too"'
The result should be: ['"    unnecessary      spaces  here      too"', x, y, z, '"   this   one     too"']

Еще раз, я был бы очень признателен за вашу тяжелую работу, чтобы помочь мне найти решения для проблем, которые у меня возникли, и если есть что-то, что я сделал неправильно или неправильно, скажите мне, где и как я должен это исправить :)

Спасибо :)

Позвольте мне обратить ваше внимание на онлайн-парсер регулярных выражений по адресу regex101.com. Позвольте мне также указать вам на \s и \s+ , регулярные выражения для одного пробела или одного или нескольких пробелов.

rajah9 09.04.2022 15:08

^ Используйте regex101 для создания и тестирования ваших регулярных выражений, прежде чем внедрять их в свой токенизатор, это сэкономит вам много времени на отладку.

Willothy 10.04.2022 01:44

Хм, я не использую регулярные выражения все время, но сейчас я хочу придумать что-то новое, например, попытаться обойти регулярные выражения, и ваши предложения могут мне очень помочь, спасибо :)

EintsWaveX 10.04.2022 06:35
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
28
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Говоря о языках программирования, string.split() и вложенных циклов будет недостаточно. Языки программирования обычно разбивают это на два этапа: токенизатор или лексер и синтаксический анализатор. Токенизатор принимает входную строку (код на вашем языке) и возвращает список токенов, представляющих ключевые слова, идентификаторы и т. д. В вашем коде это каждый элемент результата.

В любом случае, вы, вероятно, захотите немного изменить структуру своего кода. Для токенизатора вот некоторый псевдокод в стиле python:

yourcode = input
tokens = []
cursor = 0
while cursor < len(yourcode):
    yourcode = yourcode[cursor:-1] # remove previously scanned tokens
    match token regex from list of regexes
    if match == token:
        add add token of matched type to tokens
        cursor += len(matched string)
    elif match == whitespace:
        cursor += len(matched whitespace)
    else throw error invalid token

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

Тем не менее, для первого проекта языка программирования создание токенизатора и синтаксического анализатора вручную, вероятно, не лучший способ, поскольку он может очень быстро стать чрезвычайно сложным, хотя это отличный опыт, когда вы освоитесь с основами. Я бы рассмотрел возможность использования генератора парсеров. Я использовал один из них под названием СЛИ с Python, а также PLY (предшественник SLY) с хорошими результатами. Генераторы синтаксических анализаторов берут grammar, описание вашего языка в определенном формате, и выводят программу, которая может анализировать ваш язык, чтобы вы могли больше беспокоиться о функциональности самого языка, чем о том, как вы анализируете ввод текста/кода.

Также, возможно, стоит провести дополнительные исследования, прежде чем приступать к реализации. В частности, я бы порекомендовал прочитать об Abstract Syntax Trees и алгоритмах синтаксического анализа, в частности recursive descent, который вы бы написали, если бы создали парсер вручную, и LALR(1) (просмотр слева направо), который генерирует SLY.

AST — это выходные данные синтаксического анализатора (то, что делает для вас генератор синтаксического анализатора) и используются для интерпретации или компиляции вашего языка. Они имеют фундаментальное значение для создания языков программирования, поэтому я бы начал с них. Это видео объясняет синтаксические деревья, а также есть много видео, посвященных разбору Python. Эта серия также охватывает использование SLY для создания простого языка на python.

РЕДАКТИРОВАТЬ: Что касается конкретного разбора знака @ перед строкой, я бы рекомендовал использовать один тип токена для знака @, а другой — для вашего строкового литерала. В вашем синтаксическом анализаторе вы можете проверить, является ли следующий токен строковым литералом, когда синтаксический анализатор встречает символ @. Это уменьшит сложность за счет разделения ваших регулярных выражений, а также позволит вам повторно использовать токены, если вы реализуете функциональность, которая также использует @ или строковые литералы в будущем.

Другие вопросы по теме