Мы используем строки регулярного выражения нулевой ширины, чтобы указать места в строке аминокислотных символов (в основном 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);