( Редактировать: Я много исправил этот ответ, так как много итераций обратной связи; ниже приведены мои выводы по этому вопросу)
Разбор сложного языка является сложной задачей, поэтомуЯ предполагаю, что вы сузили свою проблему до обработки разделенного запятыми списка значений токенов (таких как строки, числа, простые идентификаторы и т. Д., А не сложных выражений).Если я ошибаюсь, у вас, вероятно, есть большая проблема в ваших руках, чем вы думаете.В этом случае я бы предложил этот вопрос в качестве отправной точки.
Самое простое решение - разбиение на ,
- не работает в основном из-за строк, так как запятая можетпоявляются внутри строки.Разбор строки является простой задачей, при условии, что вы имеете дело с escape-символами правильно: он начинается с кавычки, имеет ноль или более символов и заканчивается другой кавычкой.
В большинстве языков, еслистрока ограничена '
, вы можете избежать кавычки в ней, используя \'
.SQL интерпретирует ''
внутри строки как экранированную кавычку.Если вы знаете, что будет присутствовать только одна из этих форм, вы можете игнорировать другую.В моем ответе ниже я решил включить оба.
Кроме того, некоторые языки допускают использование одинарных кавычек ('
) и двойных кавычек ("
) для разделения строки.Применяются те же наблюдения о сбежавших персонажах.Мое решение также работает с обеими формами.
Помимо строк, также важно указать, какие символы являются допустимыми для аргумента.Для простоты я предположил, что это будет «все, что не является запятой».По той же причине мое предлагаемое решение будет принимать любое количество строк и нестроковых значений и сгруппирует их вместе, возвращая их как единый объект (повторяя, что если ожидаются сложные выражения, вместо этого следует использовать более общую технику синтаксического анализаэтого простого решения).
Одним из способов реализации этого было бы циклически проходить символы, применяя приведенную выше логику, как вы делали в своем недавнем обновлении.Другой будет использовать регулярное выражение.Регулярное выражение имеет как плюсы лучшую производительность (обычно) и более чистый код, менее подверженный ошибкам.Основным недостатком является сложность самого регулярного выражения, поскольку «плотный» формат может быть сложнее для понимания / поддержки.
Тогда будет предложено мое предлагаемое регулярное выражение (для удобства чтения добавлены пробелы / новые строки):
(
(?: \' (?: ['\\]\' | [^'] )* \' |
\" (?: ["\\]\" | [^"] )* \" |
[^,'"]
)+
)
(?: \, | $)
В кратком формате:
((?:\'(?:['\\]\'|[^'])*\'|\"(?:["\\]\"|[^"])*\"|[^,'"])+)(?:\,|$)
Каждая строка принимает в качестве «символов» либо экранированные кавычки ('
или \
, сопровождаемые '
), либо все, что не является кавычкой.За совпадением (большая группа захвата) должен следовать либо ,
, либо конец ввода.
Живой пример приведенного выше регулярного выражения можно увидеть здесь (примериспользует Ruby, но должен одинаково работать в C #).Пока все входные данные совпадают (т. Е. Не существует несоответствующей подстроки), каждое совпадение будет правильно захватывать аргумент. Предупреждение: искаженные входы будут давать неправильные выходы, поэтому приведенное выше регулярное выражение должно не использоваться для проверки.
Чтобы использовать это решение в своем коде C #, вы можете использоватьRegex.Matches
:
MatchCollection matches = Regex.Matches(strArguments, "((?:\'(?:['\\]\'|[^'])*\'|\"(?:["\\]\"|[^"])*\"|[^,'"])+)(?:\,|$)");
string[] arguments = from m in matches select m.Captures[1].Value;
Как отмечено выше, вы также должны убедиться, что совпадения охватывают весь ввод.Я оставляю это как упражнение для читателя ...;)
Примечания:
- Я предполагаю, что результаты
Matches
не являютсяперекрытия;если я ошибаюсь, приведенный выше код должен быть адаптирован для каждого совпадения, начиная с индекса, который заканчивается в предыдущем; - Я также, как обычно, предполагаю, что группа захвата # 0 будет целикомсовпадение, и # 1 будет первой группой захвата.