JavaScript 正则表达式以任意顺序匹配多个可选字符串

JavaScript regex to match multiple optional strings, in any order

我已经为此苦苦思索了一段时间,想不通。我在 Regex to match string containing two names in any order 中看到环视可用于查找以任何顺序出现的单词。我在 post:

的示例中添加了一些额外的组
const regex = /^(?=.*\b(jack)\b)(?=.*\b(james)\b).*$/;
"hi james this is jack".match(regex);
  // => ["hi james this is jack", "jack", "james"]

不过,我也想让这两个词都可选。也就是说,像这样:

"hi james this is jack".match(someMagicRegex);
  // => ["hi james this is jack", "jack", "james"]

"hi this is jack".match(someMagicRegex);
  // => ["hi this is jack", "jack", undefined]

"hi james".match(someMagicRegex);
  // => ["hi james", undefined, "james"]

重要的是比赛保持正确的顺序。也就是说 jack 匹配总是匹配数组中的第二个元素。

我试过在不同的地方添加 ?(包括在新分组之后),但我没有尝试产生预期的结果。

这样的事情可能吗?


UPDATE:更具体地说,我将在一系列 CSS 媒体查询中使用它,并希望匹配可选的 min-width: Xpxmax-width: Ypx 表达式:

"only screen and (min-width: 500px) and (max-width: 599px)".match(someMagicRegex);
  // => ["...", "500", "599"]

"only screen and (min-width: 500px)".match(someMagicRegex);
  // => ["...", "500", undefined]

"(max-width: 599px)".match(someMagicRegex);
  // => ["...", undefined, "599"]

(第二个匹配项是最小宽度值的数字部分,第三个匹配项是最大宽度值的数字部分。)

UPDATE 这是一个工作示例。我使用了 2 个正则表达式。首先在CSSfile/string中找class或者tag,第二个正则表达式就是找你要的属性

var fileCSS='.entry-meta {position: relative; top: 5px; left: 5px; font-size: 0.8em; line-height: 18px; color: #aaa; } .entry-footer { display: inline; color: white; margin: 0 2em; padding: 0; font-size: 0.8em; line-height: 18px; } div { MIN-width: 200px; display: block; max-width: 80% ; position: relative; background: rgba(255,255,255,0.05); padding-bottom: 20px; } img { width: 640px; min-width: 12vh ;height: auto; max-width: 800px; margin-bottom: 10px; }';

var properties = ['min-width', 'max-width'];

function pMatch(CSS, classOrTag, propertiesToFind) {
 var foundProperties=[]; var found=null;
 mainREGEX= new RegExp(classOrTag+"\s*[{][()#\"'/\*a-z0-9\s:%;*,.=-]*[}]", 'i');
 var found=CSS.match(mainREGEX)[0];
 if(found!==null) {
  for(a=0; a<propertiesToFind.length; a++) {
   propertyREGEX=new RegExp('('+propertiesToFind[a]+'\s?:\s?[0-9.]+[a-z%\s]+).?;', 'i');
   var property=found.match(propertyREGEX);
   property?foundProperties.push(property[1]):foundProperties.push('undefined');
  }
 }
 return foundProperties;
}
console.log(pMatch(fileCSS, 'div', properties));
console.log(pMatch(fileCSS, '.entry-meta', properties));
console.log(pMatch(fileCSS, 'img', properties));

不确定您是否需要完整匹配作为匹配数组 (?) 中的第一个结果,但这可以给您一个想法。没有 'magic regex'(至少对我而言),只是普通的正则表达式 array,带有捕获组:

regex = ["min-width:\s*(\d+)px","max-width:\s*(\d+)px"];

str = "only screen and (min-width: 500px) and (max-width: 599px)";

//str = "only screen and (min-width: 500px)"; 

//str="(max-width: 599px)";


matches = [];

for( i = 0; i < regex.length; i++ ) {
    if( RegExp(regex[i]).exec(str) ) {
        matches.push(RegExp(regex[i]).exec(str)[1]);
    } else {
        matches.push(undefined)
    }
}

console.log(matches);

测试用例 2:

regex = ["min-width:\s*(\d+)px","max-width:\s*(\d+)px"];



str = "only screen and (min-width: 500px)"; 

//str="(max-width: 599px)";


matches = [];

for( i = 0; i < regex.length; i++ ) {
    if( RegExp(regex[i]).exec(str) ) {
        matches.push(RegExp(regex[i]).exec(str)[1]);
    } else {
        matches.push(undefined)
    }
}

console.log(matches);

测试用例 3:

regex = ["min-width:\s*(\d+)px","max-width:\s*(\d+)px"];



str="(max-width: 599px)";


matches = [];

for( i=0; i < regex.length; i++ ) {
    if( RegExp(regex[i]).exec(str) ) {
        matches.push(RegExp(regex[i]).exec(str)[1]);
    } else {
        matches.push(undefined)
    }
}

console.log(matches);

抱歉,我的答案在 python 中,但它在任何具有环视和反向引用的语言中都应该相同。

以下代码与您的所有三个 test-cases 都正确匹配,我希望它在几乎任何情况下都能正确匹配:

import re

strings = ["only screen and (min-width: 500px) and (max-width: 599px)", "only screen and (min-width: 500px)", "(max-width: 599px)"]

regex = re.compile(r'(min|max)-width:\s*(\d+)px(.*(?!)(max|min)-width:\s*(\d+)px)?')
for string in strings:
    match = re.search(regex, string)
    print
    print string
    if match:
        term_1 = match.group(1)
        value_1 = match.group(2)
        term_2 = match.group(4)
        value_2 = match.group(5)
        print "Match!\n{} {}".format(term_1+"-width:", value_1)
        if term_2:
            print "{} {}".format(term_2+"-width:", value_2)
    else:
        print "Not a match"

当我 运行 它时,我得到了这个输出:

only screen and (min-width: 500px) and (max-width: 599px)
Match!
min-width: 500
max-width: 599

only screen and (min-width: 500px)
Match!
min-width: 500

(max-width: 599px)
Match!
max-width: 599

Jason Cohen 对 this 问题的回答解释了关键思想。他解释说前瞻(或在这种情况下为负前瞻)意味着 "match expr but after that continue matching at the original match-point."

在我这里的示例中,先行检查以确保它查看的不是它在开头匹配的相同字符串,然后检查在同一点是否存在 maxmin。请注意,在第一个 px 之后,甚至 .* 也被括在括号中。这可以防止它表现得过于贪婪。此外,整个第二个术语都用 ? 标记,这样即使找不到第二个匹配项,字符串仍会匹配。

在这里你有另一个解决方案。它使用 RegExp 来匹配模式,并使用 while 来存储值:

function getMatches (str) {
    var reg = /(min|max)-width\s*:\s*(\d*\.?\d+)/g,
        ret = [undefined, undefined],
        arr;
    while ((arr = reg.exec(str)) !== null) {
        ret[+(arr[1] === "max")] = arr[2];
    }
    return ret;
}

Jsfiddle 示例:https://jsfiddle.net/elchininet/bwg1onk6/