我们使用零宽度正则表达式字符串来指定氨基酸符号字符串(基本上是 A-Z)中有效切割位点的位置。例如,蛋白水解 enzyme 胰蛋白 enzyme 在 K 或 R 之后裂解,除非后跟 P ((?<=[KR])(?!P)
)。我想将这些正则表达式转换为在该领域也很常见的“剪切/不剪切”符号。例如,胰蛋白 enzyme 在“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 的“实验性”BOOST_REGEX_MATCH_EXTRA 功能。有没有更好的方法来做我正在做的事情?我是否遗漏了零宽度正则表达式中的其他一些正则表达式可能性?
这是我对涵盖许多简单案例的现有代码进行单元测试的伪代码。当“cut”字段对应于后视时,“sense”成员为“C”,当“cut”字段对应于前视时,“sense”成员为“N”。当前的 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);
最佳答案
据我了解,情况是,您有一个现有正则表达式库,当应用于氨基酸序列的常见字符串表示时,可以识别蛋白水解 enzyme 的可能切点。
您想自动生成正则表达式隐含的切点的标准文本描述。
观察:
您不需要能够解析任意正则表达式,您只需要能够解析库中实际拥有的案例。
您不一定需要解析所有这些。特别难的可以踢出来手工做,只要数量不多。
我真的认为您需要执行以下操作。
pepXMLSpecificity 需要返回一个或多个描述,即
vector<struct PepXMLSpecificity>
,因为可以编写正则表达式来组合任意正则表达式 cf。 jpalacek 的评论。您应该处理您的正则表达式库的实际内容,从常见情况开始逐步深入,然后为每种常见类型的正则表达式添加特殊情况,直到您获得全部(或至少足够多)让你的老板满意)。
关于c++ - 使用正则表达式解析零宽度正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8899343/