Разбор регулярного выражения нулевой ширины с регулярным выражением - PullRequest
2 голосов
/ 17 января 2012

Мы используем строки регулярного выражения нулевой ширины, чтобы указать места в строке аминокислотных символов (в основном A-Z), которые являются действительными сайтами расщепления. Например, протеолитический фермент трипсин расщепляется после K или R, за исключением случаев, когда за ним следует P ((?<=[KR])(?!P)). Я хочу преобразовать эти регулярные выражения в нотацию «вырезать / не вырезать», также распространенную в этой области. Например, трипсин режет после «KR» без надреза «P». Моя первая попытка это работает для простых случаев:

// match zero or one regex term like (?<=[KR]) or (?<=K) or (?<![KR]) or (?<!K)
// followed by zero or one term like (?=[KR]) or (?=K) or (?![KR]) or (?!K)
boost::regex cutNoCutRegex("(?:\\(+\\?<([=!])(\\[[A-Z]+\\]|[A-Z])\\)+)?(?:\\(+\\?([=!])(\\[[A-Z]+\\]|[A-Z])\\)+)?");

Без выхода C ++ это:

(?:\(+\?<([=!])(\[[A-Z]+\]|[A-Z])\)+)?(?:\(+\?([=!])(\[[A-Z]+\]|[A-Z])\)+)?

Я хотел бы изменить это, чтобы поддерживать несколько более сложные регулярные выражения, такие как множественные символы, группы без захвата, наборы символов, диапазоны в наборах символов, наборы с отрицанием и начало / конец строки: (?<=K|R) или (?<=(?:K)|(?:R)) или (?<=[^A-JL-QS-Z]) или (?<=^M|[KR])

Эти дополнительные функции, похоже, взрывают сложность регулярного выражения. Я уверен, что мне нужно включить «экспериментальную» функцию BOOST_REGEX_MATCH_EXTRA в Boost.Regex. Есть ли лучший способ сделать то, что я делаю? Я пропускаю некоторые другие возможности регулярных выражений в регулярных выражениях нулевой ширины?

Вот псевдокод для моих модульных тестов для существующего кода, охватывающий многие простые случаи. Элементом «sense» является «C», когда поле «cut» соответствует прогнозу, и «N», когда поле «cut» соответствует прогнозу. Текущая функция pepXMLSpecificity () может инвертировать набор символов, если получится более короткий список.

struct PepXMLSpecificity { std::string cut, no_cut, sense; };
void unit_assert_equal(string expected, string actual);

"(?<=[QWERTY])(?=[QWERTY])"
result = pepXMLSpecificity(ez);
unit_assert_equal("C", result.sense);
unit_assert_equal("QWERTY", result.cut);
unit_assert_equal("ABCDFGHIJKLMNOPSUVZ", result.no_cut);

"(?<![QWERTY])(?![QWERTY])"
result = pepXMLSpecificity(ez);
unit_assert_equal("C", result.sense);
unit_assert_equal("ABCDFGHIJKLMNOPSUVZ", result.cut);
unit_assert_equal("QWERTY", result.no_cut);

"(?<=[QWERTY])"
result = pepXMLSpecificity(ez);
unit_assert_equal("C", result.sense);
unit_assert_equal("QWERTY", result.cut);
unit_assert_equal("", result.no_cut);

"(?=[QWERTY])"
result = pepXMLSpecificity(ez);
unit_assert_equal("N", result.sense);
unit_assert_equal("QWERTY", result.cut);
unit_assert_equal("", result.no_cut);

"(?<![QWERTY])"
result = pepXMLSpecificity(ez);
unit_assert_equal("C", result.sense);
unit_assert_equal("ABCDFGHIJKLMNOPSUVZ", result.cut);
unit_assert_equal("", result.no_cut);

"(?![QWERTY])"
result = pepXMLSpecificity(ez);
unit_assert_equal("N", result.sense);
unit_assert_equal("ABCDFGHIJKLMNOPSUVZ", result.cut);
unit_assert_equal("", result.no_cut);

// the following tests aren't supported yet

"(?<=^M)|(?<=[KR])"
unit_assert_equal("N", result.sense);
unit_assert_equal("KR", result.cut); // the 'M' part is dropped
unit_assert_equal("", result.no_cut);

"(?<=K|R)"
unit_assert_equal("C", result.sense);
unit_assert_equal("KR", result.cut);
unit_assert_equal("", result.no_cut);

"(?<=(?:K)|(?:R))"
unit_assert_equal("C", result.sense);
unit_assert_equal("KR", result.cut);
unit_assert_equal("", result.no_cut);

"(?<=[^A-JL-QS-Z])(?!P)"
unit_assert_equal("C", result.sense);
unit_assert_equal("KR", result.cut);
unit_assert_equal("P", result.no_cut);

1 Ответ

1 голос
/ 19 января 2012

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

Вы хотите автоматически создать стандартное текстовое описание точек отсчета, подразумеваемых регулярным выражением.

Замечания:

  • Вам не нужно разбирать произвольные регулярные выражения, вам нужно только уметь анализировать случаи, которые у вас есть в вашей библиотеке.

  • Вам не обязательно анализировать их все. Особо сложные из них можно было выкинуть и сделать вручную, если их было не слишком много.

Действительно, я думаю, вам нужно сделать следующее.

  1. pepXMLSpecificity должен возвращать одно или более описаний, то есть vector<struct PepXMLSpecificity>, так как регулярное выражение может быть создано для объединения произвольных регулярных выражений, ср. Комментарий jpalacek.

  2. Вам следует разобраться с фактическим содержимым вашей библиотеки регулярных выражений, начиная с общих случаев и заканчивая, и просто добавлять специальные случаи для каждого общего типа регулярных выражений, пока вы не получите их все (или, по крайней мере, их достаточно). чтобы удовлетворить вашего босса).

...