1

我正在尝试在 Javasacript 中提取 JPA 命名参数。这是我能想到的算法

const notStrRegex = /(?<![\S"'])([^"'\s]+)(?![\S"'])/gm
const namedParamCharsRegex = /[a-zA-Z0-9_]/;

/**
 * @returns array of named parameters which,
 * 1. always begins with :
 * 2. the remaining characters is guranteed to be following {@link namedParamCharsRegex}
 *
 * @example
 * 1. "select * from a where id = :myId3;" -> [':myId3']
 * 2. "to_timestamp_tz(:FROM_DATE, 'YYYY-MM-DD\"T\"HH24:MI:SS')" -> [':FROM_DATE']
 * 3. "TO_CHAR(ep.CHANGEDT,'yyyy=mm-dd hh24:mi:ss')" -> []
 */
export function extractNamedParam(query: string): string[] {
  return (query.match(notStrRegex) ?? [])
    .filter((word) => word.includes(':'))
    .map((splittedWord) => splittedWord.substring(splittedWord.indexOf(':')))
    .filter((splittedWord) => splittedWord.length > 1) // ignore ":"
    .map((word) => {
      // i starts from 1 because word[0] is :
      for (let i = 1; i < word.length; i++) {
        const isAlphaNum = namedParamCharsRegex.test(word[i]);
        if (!isAlphaNum) return word.substring(0, i);
      }
      return word;
    });
}

我受到 https://stackoverflow.com/a/11324894/12924700中的解决方案的启发, 以过滤掉所有用单引号/双引号括起来的字符。

虽然上面的代码实现了上面的 3 个用例。但是当用户输入

const testStr  = '"user input invalid string \' :shouldIgnoreThisNamedParam \' in a string"'
extractNamedParam(testStr) // should return [] but it returns [":shouldIgnoreThisNamedParam"] instead

我确实访问了 hibernate 的源代码,看看如何在那里提取命名参数,但我找不到正在做这项工作的算法。请帮忙。

4

1 回答 1

1

您可以使用

/"[^\\"]*(?:\\[\w\W][^\\"]*)*"|'[^\\']*(?:\\[\w\W][^\\']*)*'|(:\w+)/g

仅获取第 1 组值。请参阅正则表达式演示。正则表达式匹配单引号/双引号之间的字符串,并: 在所有其他上下文中捕获 + 一个或多个单词字符。

请参阅 JavaScript 演示:

const re = /"[^\\"]*(?:\\[\w\W][^\\"]*)*"|'[^\\']*(?:\\[\w\W][^\\']*)*'|(:\w+)/g;
const text = "to_timestamp_tz(:FROM_DATE, 'YYYY-MM-DD\"T\"HH24:MI:SS')";
let matches=[], m;
while (m=re.exec(text)) {
  if (m[1]) {
    matches.push(m[1]);
  }
}
console.log(matches);

详情

  • "[^\\"]*(?:\\[\w\W][^\\"]*)*"- a ",然后是除"and \( [^"\\]*) 之外的零个或多个字符,然后是任何转义字符 ( ) 的零个或多个重复,然后是除and\\[\w\W]之外的零个或多个字符,然后是 a"\"
  • |- 或者
  • '[^\\']*(?:\\[\w\W][^\\']*)*'- a ',然后是除'and \( [^'\\]*) 之外的零个或多个字符,然后是任何转义字符 ( ) 的零个或多个重复,然后是除and\\[\w\W]之外的零个或多个字符,然后是 a'\'
  • |- 或者
  • (:\w+)- 第 1 组(这是我们需要获取的值,其余的仅用于消耗一些必须忽略匹配的文本):一个冒号和一个或多个单词字符。
于 2021-08-19T11:15:24.390 回答