Я работаю над созданием веб-компонентов, и мне нужно регулярное выражение, которое фиксирует случаи интерполяции строк в строке шаблона. Например, со следующей строкой:
<img src = "${this.image}"/><h5>${this.title}</h5><p>${this.description}</p>
Случаи интерполяции строк находятся внутри ${} и могут быть захвачены с помощью: (this(\.\w+)).
Но я не хочу захватывать первый экземпляр, потому что он находится внутри атрибута.
Я попробовал выражение ((?<!".+)this(\.\w+)+(?!.+")), которое работает с многострочной строкой (каждый тег в отдельной строке), но теперь с одной строкой.
Вот моя демо RegExr.
Возможно, кто-то с большим опытом в RegEx может мне помочь.
Чтобы вопрос был простым и по существу, я не упомянул об этом...
Причина, по которой я хочу это сделать, заключается в том, что я использую Lit для создания веб-компонентов, я уже создал функцию интерполятора, которая возвращает Lit TemplateResult , теперь я хочу выделить данные с помощью тегов <b>, поэтому я хочу замените совпадения RexEx директивой unsafeHTML, но unsafeHTML выдает ошибку внутри атрибутов.
Вот моя функция интерполятора:
export function FillTemplate(templateString: string, data: any): TemplateResult {
let regex = /((?<!".+)this(\.\w+)+(?!.+"))/g;
if (regex.test(templateString)) {
templateString = templateString.replace(/((?<!".+)this(\.\w+)+(?!.+"))/g, "unsafeHTML($1)");
}
return new Function('html', 'unsafeHTML', "return html`"+templateString +"`;").call(data, html, unsafeHTML);
};
.... Я также подумаю об этом, может быть, мне лучше проверить ключи объекта, а не строку шаблона...



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, что это должно сработать для вас:
[^"]\$\{(this\.\w+)
Для этого потребуются только интерполяции, которым не предшествует "
Используйте следующее регулярное выражение:
[^ = "]{2}\${(\S+?)}
= и их значение будет в кавычках. Таким образом, [^ = "]{2} гарантирует, что мы сопоставляем два символа, которые не являются = и ".(\S+?) затем лениво захватывает необходимые данные в группу захвата.[^=][^"] будет точнее, чем [^ = "]{2}, и исключить ==, например "=Вы можете использовать отрицательный просмотр назад для учета атрибута в кавычках: ?<!=["'])\$\{this(?:\.\w+)+\}. Это исключит src = "${this.image}" в вашем примере, но вы получите ложное срабатывание для текста HTML, например <p>Quote: "${this.quote}"</p>
Вы можете использовать отрицательный просмотр назад для учета атрибута в кавычках в теге HTML: (?<!<\w+ (\w+=["'][^"']*["'] )*\w+=["'])\$\{this(?:\.\w+)+\}.
Вот пример с обоими регулярными выражениями:
const regex1 = /(?<!["'])\$\{this(?:\.\w+)+\}/g;
const regex2 = /(?<!<\w+ (\w+=["'][^"']*["'] )*\w+=["'])\$\{this(?:\.\w+)+\}/g;
[
'<img src = "${this.image}"/><h5>${this.title}</h5><p>${this.description}</p><p>Quote: "${this.quote}"</p>',
'<img foo = "bar" src = "${this.image}"/><h5>${this.title}</h5><p>${this.description}</p><p>Quote: "${this.quote}"</p>'
].forEach(str => {
console.info(str);
console.info('- regex1:', str.match(regex1));
console.info('- regex2:', str.match(regex2));
});Объяснение regex2:
(?<! -- отрицательный просмотр назад<\w+ -- начало тега HTML и пробел <img (\w+=["'][^"']*["'] )* -- 0+ атрибутов формы attr = "value" с пробелом в конце\w+=["'] -- начало атрибута, например src = " или src=') -- отрицательный просмотр назад\$\{this -- буквально ${this(?:\.\w+)+ -- группа без захвата для 1+ паттернов .something\} -- буквально }Примечание. Если ваш движок регулярных выражений не поддерживает отрицательный просмотр назад (особенно Safari), вы можете изменить его на группу захвата и восстановить ее с помощью .replace()
Я собираюсь принять это как ответ, поскольку он является наиболее полным и объясняет выражение. С Рождеством!
Этот также будет учитывать атрибуты (вопреки тому, что спрашивали).
Альтернативное решение вместо регулярного выражения (и если вы доверяете data) будет использовать конструктор функций и позволить синтаксическому анализатору JavaScript интерпретировать и оценивать строку как литерал шаблона и выполнять за вас желаемую работу:
const interpolate = (str, data) =>
Function("return (`" + str + "`);").call(data);
// Use like:
const str = '<img src = "${this.image}"/><h5>${this.title}</h5><p>${this.description}</p>';
const data = {
title: "Lorem ipsum",
description: "Dolor sit amet",
image: "https://i.stack.imgur.com/zH7ZS.jpg?s=64&g=1",
};
document.body.insertAdjacentHTML("beforeend", interpolate(str, data));Кроме того, если вы обнаружите, что this в вашем шаблоне слишком повторяется, вы можете напрямую использовать ключи объекта и .apply() значения, как в этом решении:
const interpolate = (str, data) =>
Function(...Object.keys(data), "return (`" + str + "`);").apply(null, Object.values(data));
// Use like:
const str = '<img src = "${image}"/><h5>${title}</h5><p>${description}</p>';
const data = {
title: "Lorem ipsum",
description: "Dolor sit amet",
image: "https://i.stack.imgur.com/zH7ZS.jpg?s=64&g=1",
};
document.body.insertAdjacentHTML("beforeend", interpolate(str, data));или, как указано выше (без this, с использованием ключей объекта) без небезопасной оценки, было бы с использованием String.prototype.replace() и регулярного выражения, такого как /\$\{([^}]+)\}/g:
const interpolate = (str, data) =>
str.replace(/\$\{([^}]+)\}/g, (_, k) => data[k]);
const str = '<img src = "${image}"/><h5>${title}</h5><p>${description}</p>';
const data = {
title: "Lorem ipsum",
description: "Dolor sit amet",
image: "https://i.stack.imgur.com/zH7ZS.jpg?s=64&g=1",
};
document.body.insertAdjacentHTML("beforeend", interpolate(str, data));+1 за использование моего изображения и за функцию interpolate. Однако я создал функцию, которая возвращает LitElement TemplateResult... Я обновлю свой вопрос, чтобы показать свою функцию
что-то вроде ... /(?<!=["'])\$\{this\.(?<key>[^}]+)\}/g ... использует отрицательный взгляд назад.