COUNTER PRIMITIVE
Давайте определим функции обратного вызова следующим образом:
// ****************************
// COUNTER BEING A PRIMITIVE
// ****************************
function test1() {
for (var i=0; i<2; i++) {
setTimeout(function() {
console.log(i);
});
}
}
test1();
// 2
// 2
По завершении таймаута он будет печатать 2 для обоих. Это связано с тем, что функция обратного вызова обращается к значению, основанному на лексической области , где была определена функция.
Чтобы передать и сохранить значение при определении обратного вызова, мы можем создать замыкание , чтобы сохранить значение до вызова обратного вызова. Это можно сделать следующим образом:
function test2() {
function sendRequest(i) {
setTimeout(function() {
console.log(i);
});
}
for (var i = 0; i < 2; i++) {
sendRequest(i);
}
}
test2();
// 1
// 2
Теперь в этом особенность: «Примитивы передаются по значению и копируются. Таким образом, когда ограничение определено, они сохраняют значение из предыдущего цикла».
COUNTER BEING OBJECT
Поскольку у закрытий есть доступ к родительским переменным функции через ссылку, этот подход будет отличаться от такового для примитивов.
// ****************************
// COUNTER BEING AN OBJECT
// ****************************
function test3() {
var index = { i: 0 };
for (index.i=0; index.i<2; index.i++) {
setTimeout(function() {
console.log('test3: ' + index.i);
});
}
}
test3();
// 2
// 2
Итак, даже если для переменной, передаваемой как объект, создается замыкание, значение индекса цикла не будет сохранено. Это означает, что значения объекта не копируются, а к ним обращаются через ссылку.
function test4() {
var index = { i: 0 };
function sendRequest(index, i) {
setTimeout(function() {
console.log('index: ' + index);
console.log('i: ' + i);
console.log(index[i]);
});
}
for (index.i=0; index.i<2; index.i++) {
sendRequest(index, index.i);
}
}
test4();
// index: { i: 2}
// 0
// undefined
// index: { i: 2}
// 1
// undefined
Вам нужен сдержанный жадный токен :
abc(?:(?!abc|xyz|123).)*123(?:(?!abc|xyz).)*xyz
См. демонстрацию regex
Чтобы убедиться, что она соответствует через строки, используйте флаг re.DOTALL
при компиляции регулярного выражения.
Обратите внимание, что для достижения более высокой производительности с таким тяжелым шаблоном вам следует рассмотреть возможность его развертывания.
Сведения о шаблоне:
abc
- соответствие abc
(?:(?!abc|xyz|123).)*
- сопоставить любой символ, который не является отправной точкой для последовательностей символов abc
, xyz
или 123
123
- буквальная строка 123
(?:(?!abc|xyz).)*
- любой символ, который не является исходной точкой для последовательностей символов abc
или xyz
xyz
- конечная подстрока xyz
См. Диаграмму ниже (если используется re.S
, .
будет означать AnyChar
):
См. Демонстрацию Python :
import re
p = re.compile(r'abc(?:(?!abc|xyz|123).)*123(?:(?!abc|xyz).)*xyz', re.DOTALL)
s = "abc 123 xyz\nabc abc 123 xyz\nabc text 123 xyz\nabc text xyz xyz"
print(p.findall(s))
// => ['abc 123 xyz', 'abc 123 xyz', 'abc text 123 xyz']
Комментарий на hvd вполне уместен, и это только пример. В SQL, например, я думаю, что было бы более ясным:
where val like 'abc%123%xyz' and
val not like 'abc%abc%' and
val not like '%xyz%xyz'
Я предполагаю, что что-то совершенно похожее сделать в других средах.
Использование PCRE для решения будет:
Это использование флага m
. Если вы хотите проверить только с начала и конца строки, добавьте ^
и $
в начало и конец соответственно
abc(?!.*(abc|xyz).*123).*123(?!.*(abc|xyz).*xyz).*xyz
[/g1]
Вы можете использовать lookaround.
/^abc(?!.*abc).*123.*(?<!xyz.*)xyz$/g
(я его не тестировал.)