使用XRegExp测试字母数字字符串结果不符,求排查问题
为什么两个看似等价的正则表达式测试结果不同?
你的代码如下:
import { match } from 'ts-pattern' import XRegExp from 'xregexp' export const alphanumRegex = (action = 'validate'): RegExp | string => { const baseRegex = XRegExp.tag('gimx')`A-Z0-9` const finalRegex = XRegExp.tag(baseRegex.flags)`[${baseRegex}]+` return match(action) .returnType<RegExp | string>() .with('negate', () => negateRegex(baseRegex)) .with('validate', () => inputValidationRegex(finalRegex)) .otherwise(() => absentParamError(action, alphanumRegex.name)) } export const absentParamError = (action: string, fnName: string) => `Absent identifier '${action}' for '${fnName}()'` export const inputValidationRegex = (regex: RegExp) => XRegExp.tag(regex.flags)`^(${regex})$` export const negateRegex = (regex: RegExp) => XRegExp.tag(regex.flags)`[^${regex}]*` // Testing the regex const retVal1 = XRegExp.test('abc123', alphanumRegex('validate') ) const retVal2 = XRegExp.test('abc123', /^([A-Z0-9]+)$/gmi) console.log( {retVal1, retVal2}) // {retVal1: false, retVal2: true}
核心错误原因
问题出在两个关键的正则构建错误上:
错误定义字符范围
你用XRegExp.tag('gimx')A-Z0-9``创建的baseRegex,并不是匹配A-Z、0-9的字符范围,而是匹配字面量字符A、-、Z、0、-、9。XRegExp的模板字符串不会自动把A-Z0-9解析成正则字符范围,必须把它放在[]内才能生效。插入RegExp对象时的字符串转换问题
当你在XRegExp.tag(baseRegex.flags)[${baseRegex}]+``中插入baseRegex时,实际调用了RegExp的toString()方法,得到的是"/A-Z0-9/gimx"这个完整的正则字符串。这导致finalRegex的正则源变成了[/A-Z0-9/gimx]+,也就是匹配包含/、g、i、m、x等符号在内的字符集合,完全偏离了你原本想要的[A-Z0-9]+。
最终alphanumRegex('validate')生成的正则是^([/A-Z0-9/gimx]+)$,和你预期的^([A-Z0-9]+)$差异巨大,因此测试结果不同。
修复方案
调整代码,直接在XRegExp模板中正确定义字符范围,避免插入RegExp对象:
import { match } from 'ts-pattern' import XRegExp from 'xregexp' export const alphanumRegex = (action = 'validate'): RegExp | string => { // 直接定义正确的字符范围模板 const alphaNumRange = '[A-Z0-9]' const flags = 'gimx' return match(action) .returnType<RegExp | string>() .with('negate', () => XRegExp.tag(flags)`[^${alphaNumRange}]*`) .with('validate', () => XRegExp.tag(flags)`^(${alphaNumRange}+)$`) .otherwise(() => absentParamError(action, alphanumRegex.name)) } export const absentParamError = (action: string, fnName: string) => `Absent identifier '${action}' for '${fnName}()'` // 测试修复后的代码 const retVal1 = XRegExp.test('abc123', alphanumRegex('validate') ) const retVal2 = XRegExp.test('abc123', /^([A-Z0-9]+)$/gmi) console.log( {retVal1, retVal2}) // {retVal1: true, retVal2: true}
内容的提问来源于stack exchange,提问作者st_clair_clarke
相关产品推荐
相关产品推荐

