Это очень распространенная проблема, с которой мы сталкиваемся, борясь с «таинствами» JavaScript.
Давайте начнем с простой функции JavaScript:
function foo(){
// do something
return 'wohoo';
}
let bar = foo(); // bar is 'wohoo' here
Это простой синхронный вызов функции (где каждая строка кода выполняется одна за другой в последовательность), и результат будет таким же, как ожидалось.
Теперь добавим немного завихрения, введя небольшую задержку в нашей функции, чтобы все строки кода не выполнялись последовательно. Таким образом, он будет эмулировать асинхронное поведение функции:
function foo(){
setTimeout( ()=>{
return 'wohoo';
}, 1000 )
}
let bar = foo() // bar is undefined here
Итак, вы идете, эта задержка просто сломала функциональность, которую мы ожидали! Но что именно произошло? Ну, на самом деле это довольно логично, если вы посмотрите на код. функция foo()
после выполнения ничего не возвращает (таким образом, возвращаемое значение равно undefined
), но оно запускает таймер, который выполняет функцию после 1s, чтобы вернуть «wohoo». Но, как вы можете видеть, значение, присвоенное бару, является немедленно возвращенным материалом из foo (), а не что-либо еще, что приходит позже.
Итак, как мы решаем эту проблему?
Давайте попросим нашу функцию для ОБЕЩАНИЯ. Обещание действительно о том, что это означает: это означает, что функция гарантирует, что вы предоставите любой результат, который он получит в будущем. поэтому давайте посмотрим на это в нашей маленькой проблеме выше:
function foo(){
return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
setTimeout ( function(){
// promise is RESOLVED , when exececution reaches this line of code
resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
}, 1000 )
})
}
let bar ;
foo().then( res => {
bar = res;
console.log(bar) // will print 'wohoo'
});
Таким образом, резюме - для решения асинхронных функций, таких как вызовы на основе ajax и т. д., вы можете использовать обещание resolve
значение (которое вы намерены вернуть). Таким образом, короче говоря, вы разрешаете значение вместо возврата в асинхронных функциях.
К сожалению, для split
требуется совпадение с нулевой шириной, но оно еще не исправлено, так как довольно много неправильного кода зависит от текущего поведения, используя, например, [something]*
, как регулярное выражение. Использование таких шаблонов теперь будет генерировать FutureWarning
, а те, которые никогда не могут разбить что-либо, выкиньте ValueError
из Python 3.5 и далее:
>>> re.split(r'(?<!foo)(?=bar)', 'foobarbarbazbar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/re.py", line 212, in split
return _compile(pattern, flags).split(string, maxsplit)
ValueError: split() requires a non-empty pattern match.
Идея в том, что после определенного периода предупреждений поведение может быть изменено так, чтобы ваше регулярное выражение снова работало.
Если вы не можете использовать модуль regex
, вы можете написать свою собственную функцию разделения используя re.finditer()
:
def megasplit(pattern, string):
splits = list((m.start(), m.end()) for m in re.finditer(pattern, string))
starts = [0] + [i[1] for i in splits]
ends = [i[0] for i in splits] + [len(string)]
return [string[start:end] for start, end in zip(starts, ends)]
print(megasplit(r'(?<!foo)(?=bar)', 'foobarbarbazbar'))
print(megasplit(r'o', 'foobarbarbazbar'))
Если вы уверены, что совпадения имеют только нулевую ширину, вы можете использовать начальные расщепления для более простого кода:
import re
def zerowidthsplit(pattern, string):
splits = list(m.start() for m in re.finditer(pattern, string))
starts = [0] + splits
ends = splits + [ len(string) ]
return [string[start:end] for start, end in zip(starts, ends)]
print(zerowidthsplit(r'(?<!foo)(?=bar)', 'foobarbarbazbar'))
import regex
x="bazbarbarfoobar"
print regex.split(r"(?<!baz)(?=bar)",x,flags=regex.VERSION1)
Здесь вы можете использовать модуль regex
.
или
(.+?(?<!foo))(?=bar|$)|(.+?foo)$
Используйте re.findall
.