【问题标题】:Match text between single quotes, double quotes, or no quotes at all匹配单引号、双引号或根本没有引号之间的文本
【发布时间】:2021-07-10 04:47:47
【问题描述】:

我正在尝试解析类似 CLI 的参数,这些参数可能包含在单引号、双引号或根本没有引号中。
这是我想要得到的一个例子:

// --message "This is a 'quoted' message" --other 'This uses the "other" quotes'
const str = "--message \"This is a 'quoted' message\" --other 'This uses the \"other\" quotes'"

matchGitArgs(str) // ['--message', 'This is a \'quoted\' message', '--other', 'This uses the "other" quotes']

我发现了很多类似的问题,所以这就是它与它们的不同之处:

  • 重要的是它也匹配不在引号中的参数,并保持原始顺序
  • 应该能够解析同一字符串中的单引号和双引号参数
  • 不应与引号本身匹配:
matchGitArgs('This is "quoted"')
// Correct: ['This', 'is', 'quoted']
// Wrong: ['This', 'is', '"quoted"']
  • 它应该允许在其中包含转义引号和其他引号:
matchGitArgs('It is "ok" to use \'these\'')
// ["It", "is", "ok", "to", "use", "these"]

我已经尝试使用我在这里找到的许多不同的正则表达式模式,但它们都不满足其中一个条件。我也尝试过使用旨在解析 CLI 参数的库,但似乎它们都依赖于 process.argv(在 Node.js 中),它已经根据引号正确拆分,因此对我没有帮助。
我基本上需要做的是生成一个像process.argv 这样的数组。

它不需要是一个单一的正则表达式,一个 js/ts 函数也可以。

【问题讨论】:

  • 恐怕您认为const str = "--message \"This is a 'quoted' message\"" 包含反斜杠,但事实并非如此。 String.raw 下面的答案中使用的符号使模板字符串文字中的反斜杠 literal

标签: javascript node.js regex


【解决方案1】:

“详细”表达式和命名组特别适用于标记问题:

function* parseArgs(cmdLine) {

    const re = String.raw`
        (
            -- (?<longOpt> \w+)
            (\s+ | =)
        )

        | (
            - (?<shortOpt> \w+)
            \s+
        )

        | (
            ('
                (?<sq> (\\. | [^'])* )
            ')
            \s+
        )

        | (
            ("
                (?<dq> (\\. | [^"])* )
            ")
            \s+
        )

        | (
            (?<raw> [^\s"'-]+)
            \s+
        )

        | (?<error> \S)

    `.replace(/\s+/g, '');

    for (let m of (cmdLine + ' ').matchAll(re)) {
        let g = Object.entries(m.groups).filter(p => p[1]);

        let [type, val] = g[0];

        switch (type) {
            case 'error':
                throw new Error(m.index);
            case 'sq':
            case 'dq':
                yield ['value', val.replace(/\\/g, '')];
                break;
            case 'raw':
                yield ['value', val];
                break;
            case 'longOpt':
            case 'shortOpt':
                yield ['option', val];
        }
    }
}

//

args = String.raw`
    --message "This is \"a\" 'quoted' message"
    -s
    --longOption 'This uses the "other" quotes'
    --foo 1234
    --file=message.txt
    --file2="Application Support/message.txt"
`

for (let [type, s] of parseArgs(args))
    console.log(type, ':', s)

【讨论】:

  • 我发现了一个问题:"--file=message.txt" 被解析为 ["--file", "=message.txt"] 而不是 ["--file=message.txt"],你能帮我解决这个问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多