如何使用多个捕获组进行正则表达式替换?

问题描述

我试图允许用户使用唯一控制字符为 * 的 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 准备好字符串:

  1. 引用所有特殊的正则表达式字符,并且
  2. 将 * 的所有实例都变成 .* 或者可能是 .*?

让我们保持简单,分两步处理字符串,每一步都使用 Js.re.replace。所以正则表达式中的特殊字符列表是[^$.|?*+()。适当引用这些替换:

str.replace(/[\[\\\^\$\.\|\?\+\(\)]/g,'\$&')

这只是引用的所有特殊字符。替换规范中的 $& 表示插入匹配的内容。 然后将该结果传递给第二次替换 * 到 .*?转型。

str.replace(/*+/g,'.*?')