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: Xpx
和 max-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."
在我这里的示例中,先行检查以确保它查看的不是它在开头匹配的相同字符串,然后检查在同一点是否存在 max
或 min
。请注意,在第一个 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/
我已经为此苦苦思索了一段时间,想不通。我在 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: Xpx
和 max-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."
在我这里的示例中,先行检查以确保它查看的不是它在开头匹配的相同字符串,然后检查在同一点是否存在 max
或 min
。请注意,在第一个 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/