ChatGPT解决这个技术问题 Extra ChatGPT

将用户输入字符串转换为正则表达式

我正在用 HTML 和 JavaScript 设计一个正则表达式测试器。用户将输入一个正则表达式、一个字符串,并通过单选按钮选择他们想要测试的函数(例如搜索、匹配、替换等),当使用指定参数运行该函数时,程序将显示结果。自然会有额外的文本框来替换额外的参数等。

我的问题是从用户那里获取字符串并将其转换为正则表达式。如果我说他们不需要在输入的正则表达式周围有 //,那么他们就不能设置标志,例如 gi。所以他们必须在表达式周围有 //,但我怎样才能将该字符串转换为正则表达式?它不能是文字,因为它是一个字符串,并且我不能将它传递给 RegExp 构造函数,因为它不是没有 // 的字符串。有没有其他方法可以将用户输入字符串变成正则表达式?我是否必须用 // 解析正则表达式的字符串和标志,然后以另一种方式构造它?我应该让他们输入一个字符串,然后分别输入标志吗?


G
Gumbo

使用 RegExp object constructor 从字符串创建正则表达式:

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;

有一个带有输入字段的在线工具会很好
这样做时,您必须转义反斜杠,例如 var re = new RegExp("\\w+");
@holms regex101.com 也是一个很棒的正则表达式在线工具
我花了一段时间才看到不需要尾部斜杠
@JDSmith我在你的例子中不是这个意思。我的意思是,如果您希望双引号成为正则表达式的一部分,则需要转义双引号,前提是它是硬编码的。显然,如果字符串位于来自 <input> HTML 标记的变量中,则这些都不适用。 var re = new RegExp("\"\\w+\""); 是使用 RegExp 构造函数的硬编码正则表达式的示例,并且双引号 is 的转义是必要的。我所说的变量中的字符串的意思是您可以执行 var re = new RegExp(str); 并且 str 可能包含双引号或反斜杠而没有问题。
M
Mak
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

或者

var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);

您应该考虑识别出像 /\/ 这样的无效输入。
或者让 RegExp 构造函数失败,“在正则表达式中尾随 \”,而不是编写复杂的解析器。
注意,用户可以输入任意数量的标志,例如:/foo/ggggg。在第一个示例中,您可以将 flags 替换更改为 replace('/.*\/(?!.*(.).*\1)([gimy]*)$/', '$2')。或者对第二个示例 ^\/(.*)\/(?!.*(.).*\2)([gimy]*)$ 使用以下正则表达式,什么会将标志放在匹配组 3 中。
R
Rivenfall

这是一个单行:str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

我从 escape-string-regexp NPM 模块得到它。

尝试一下:

escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
    return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}

console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/

使用带有标志支持的标记模板文字:

function str2reg(flags = 'u') {
    return (...args) => new RegExp(escapeStringRegExp(evalTemplate(...args))
        , flags)
}

function evalTemplate(strings, ...values) {
    let i = 0
    return strings.reduce((str, string) => `${str}${string}${
        i < values.length ? values[i++] : ''}`, '')
}

console.log(str2reg()`example.com`)
// => /example\.com/u

A
Ayman Hourieh

使用 JavaScript RegExp object constructor

var re = new RegExp("\\w+");
re.test("hello");

您可以将标志作为第二个字符串参数传递给构造函数。有关详细信息,请参阅文档。


s
staabm

在我的情况下,用户输入 somethimes 被分隔符包围,有时没有。因此我添加了另一个案例..

var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
    // the parsed pattern had delimiters and modifiers. handle them. 
    var regexp = new RegExp(regParts[1], regParts[2]);
} else {
    // we got pattern string without delimiters
    var regexp = new RegExp(inputstring);
}

您始终可以使用 .split() 函数而不是长的正则表达式字符串。 regParts = inputstring.split('/') 这将使 regParts[1] 成为正则表达式字符串,而 regParts[2] 成为分隔符(假设正则表达式的设置是 /.../gim)。您可以检查是否有带有 regParts[2].length < 0 的分隔符。
@ZomoXYZ 不要使用拆分,它不会处理正则表达式中的转义 /
您可以做得更好:function stringToRegex(s, m) { return (m = s.match(/^(.)(.*?)\1([gimsuy]*)$/)) ? new RegExp(m[2], m[3]) : new RegExp(s); }
R
Richie Bendall

尝试使用以下功能:

const stringToRegex = str => {
    // Main regex
    const main = str.match(/\/(.+)\/.*/)[1]
    
    // Regex options
    const options = str.match(/\/.+\/(.*)/)[1]
    
    // Compiled regex
    return new RegExp(main, options)
}

你可以像这样使用它:

"abc".match(stringToRegex("/a/g"))
//=> ["a"]

Z
Zombo

我建议您还为特殊标志添加单独的复选框或文本字段。这样很明显,用户不需要添加任何 //。在替换的情况下,提供 两个 文本字段。这会让你的生活轻松很多。

为什么?因为否则有些用户会添加 //,而其他用户则不会。有些会出现语法错误。然后,在您剥离 // 之后,您最终可能会得到一个语法上有效的正则表达式,这与用户的意图完全不同,从而导致奇怪的行为(从用户的角度来看)。


T
Tofandel

这是我处理自定义分隔符和无效标志的一个线性函数

函数 stringToRegex(s, m) { return (m = s.match(/^([\/~@;%#'])(.*?)\1([gimsuy]*)$/)) ?新 RegExp(m[2], m[3].split('').filter((i, p, s) => s.indexOf(i) === p).join('')) : 新正则表达式; } console.log(stringToRegex('/(foo)?\/bar/i')); console.log(stringToRegex('#(foo)?\/bar##gi')); //自定义分隔符 console.log(stringToRegex('#(foo)?\/bar##gig')); //过滤掉重复的标志 console.log(stringToRegex('/(foo)?\/bar')); // 视为字符串 console.log(stringToRegex('gig')); // 当作字符串处理


仅仅因为您将 10 条语句塞进一行,它就不是一个单行 :)
10个陈述?它只是一个三元表达式,如果它是一行,它是一个单行;)如果你说它是 3 行,因为函数只是为了可读性,否则你可以做 const stringToRegex = (s, m) => (m = s.match(/^([\/~@;%#'])(.*?)\1([gimsuy]*)$/)) ? new RegExp(m[2], m[3].split('').filter((i, p, s) => s.indexOf(i) === p).join('')) : new RegExp(s);
k
kofifus

当字符串无效或不包含标志等时,这也将起作用:

function regExpFromString(q) { let flags = q.replace(/.*\/([gimuy]*)$/, '$1');如果(标志 === q)标志 = ''; let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);尝试{返回新的正则表达式(模式,标志); } 捕捉 (e) { 返回空值; } } console.log(regExpFromString('\\bword\\b')); console.log(regExpFromString('\/\\bword\\b\/gi'));


G
Gene Bo

由于较早的答案,此块可以很好地用作将可配置字符串应用于 RegEx .. 以过滤文本的通用解决方案:

var permittedChars = '^a-z0-9 _,.?!@+<>';
permittedChars = '[' + permittedChars + ']';

var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);

log.debug ('strFilterRegEx: ' + strFilterRegEx);

strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!@+]/ig, '');

A
Akshat Mahajan

您可以使用复选框请求标志,然后执行以下操作:

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);

S
Stephen Todd

更安全,但不安全。 (不能访问任何其他上下文的 Function 版本会很好。)

const regexp = Function('return ' + string)()

P
Playhi

我使用 eval 来解决这个问题。

例如:

    function regex_exec() {

        // Important! Like @Samuel Faure mentioned, Eval on user input is a crazy security risk, so before use this method, please take care of the security risk. 
        var regex = $("#regex").val();

        // eval()
        var patt = eval(userInput);

        $("#result").val(patt.exec($("#textContent").val()));
    }

userInput 上的 eval 是一个疯狂的安全风险
鲍比先生!