问题描述
我试图允许用户使用唯一控制字符为 *
的 glob 模式过滤文本字符串。在幕后,我认为过滤列表字符串最简单的方法是使用 Js.Re.test
[https://rescript-lang.org/docs/manual/latest/api/js/re#test_],和很(简单)。
暂时忽略用户过滤器字符串上的 *
,我遇到的困难是转义所有 RegEx 控制字符。具体来说,我不知道如何替换输入文本中的捕获组以创建新字符串。
到目前为止,我已经掌握了这个,但不太正确:
let input = "test^ing?123[foo";
let escapeRegExCtrl = searchStr => {
let re = [%re("/([\\^\\[\\]\\.\\|\\\\\\?\\{\\}\\+][^\\^\\[\\]\\.\\|\\\\\\?\\{\\}\\+]*)/g")];
let break = ref(false);
while (!break.contents) {
switch (Js.Re.exec_ (re,searchStr)) {
| Some(result) => {
let match = Js.Re.captures(result)[0];
Js.log2("Matching: ",match)
}
| None => {
break := true;
}
}
}
};
search -> escapeRegExCtrl
如果我忽略被跳过的字符串的“测试”部分,上面的输出将产生:
Matching: ^ing
Matching: ?123
Matching: [foo
通过上面的例子,在一天结束的时候,我想要制作的是这个(前导和跟随 .*
:
.*test\^ing\?123\[foo.*
但我不确定如何从匹配的捕获组中创建一个连续字符串。
(echo "test^ing?123[foo" | sed -r 's_([\^\?\[])_\\\1_g'
将在命令行上完成工作)
编辑
根据 Chris Maurer 的回答,JS 库中有一种方法可以满足我的需求。稍微挖掘一下就暴露了该方法的 ReasonML 代理: https://rescript-lang.org/docs/manual/latest/api/js/string#replacebyre
解决方法
让我看看我有没有这个权利;您想实现一个字符匹配器,其中除 * 之外的所有内容都是文字。大概 * 应该像在 Windows dir 命令中那样工作,匹配零个或多个字符。
此外,您希望通过将用户输入的字符串直接传递给 Regexp 匹配函数来实现它,然后对其进行适当的清理以仅处理 *。
如果我有这个权利,那么听起来您需要做两件事来为 js.re.test 准备好字符串:
- 引用所有特殊的正则表达式字符,并且
- 将 * 的所有实例都变成 .* 或者可能是 .*?
让我们保持简单,分两步处理字符串,每一步都使用 Js.re.replace。所以正则表达式中的特殊字符列表是[^$.|?*+()。适当引用这些替换:
str.replace(/[\[\\\^\$\.\|\?\+\(\)]/g,'\$&')
这只是引用的所有特殊字符。替换规范中的 $& 表示插入匹配的内容。 然后将该结果传递给第二次替换 * 到 .*?转型。
str.replace(/*+/g,'.*?')