Я могу заменить обычную строку, используя:
var strNew = strContent.replace("subject", "replacement");
Однако в приведенных выше работах обнаружено:
var strNew = strContent.replace("{subject}", "replacement");
Не работает, нужно что-то сделать?
Я пробовал:
var strNew = strContent.replace("/{/gsubject/}/g", "replacement");
Тоже не сработало...
[Изменить] Что-то очень не так, я добавил больше отладки, кстати, это запускается Node.js v21.7.1 в Windows 10.
Я читаю HTML-страницу из MariaDB, она читается в строку:
<!DOCTYPE html><html><head><meta http-equiv = "X-UA-Compatible" content = "IE=Edge" /><meta http-equiv = "content-type" content = "text/html; charset=utf-8"><meta name = "author" content = "Simon Platten"><title>Quintex, no company</title><link rel = "stylesheet" href = "/scripts/jquery/jquery-ui.min.css" class = "ui-theme"/><link rel = "stylesheet" href = "/scripts/jquery/jqwidgets/styles/jqx.base.css"/><link rel = "stylesheet" href = "/scripts/jquery/jqwidgets/styles/jqx.darkblue.css"/><link rel = "stylesheet" href = "/styles/common.css"/>
<style type = "text/css">body { background: #ffffff url("images/quintex.png") no-repeat 4px 4px; font-family: 'Open Sans', sans-serif; overflow-y: scroll; font-size: 9pt; } h1 { padding-bottom: 5px; font-size: 14pt; color: #124a9d; } a { text-decoration: none; color: #124a9d; } a:hover { text-decoration: underline; color: #124a9d; } a.mnubtn { text-decoration: none; text-align: center; color: #ffffff; } .ui-dialog-osx { -moz-border-radius: 0 0 8px 8px; -webkit-border-radius: 0 0 8px 8px; border-radius: 0 0 8px 8px; border-width: 0 8px 8px 8px; } .ui-widget-header { background: #0000ff url("/images/menubar.jpg") repeat-x scroll 50% 50%; } #svrinfo { background-color: #0000ff; text-align:center; font-weight: bold; position:abolute; font-size: 14pt; color: #ffff00; z-index: 9999; display: none; } #loading { transform: translate(-50%, -50%); position: fixed; z-index: 99999; left:50%; top:50%; } footer { text-align: center; position:absolute; font-size: 9pt; width: 100%; bottom: 0px; }
</style><script type = "text/javascript" src = "/scripts/modernizr.js"></script><script type = "text/javascript" src = "/scripts/jquery/jquery-2.2.1.min.js"></script><script type = "text/javascript" src = "/scripts/jquery/jquery-ui.min.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxcore.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxbuttons.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxscrollbar.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxlistbox.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxcombobox.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxpasswordinput.js"></script><script type = "text/javascript" src = "/scripts/jquery/jqwidgets/jqxbuttons.js"></script><script type = "text/javascript" src = "/socket.io/socket.io.js"></script><script type = "text/javascript" src = "/scripts/consts.js"></script>
<script type = "text/javascript" language = "javascript">
<!--
var strSocketServer = "ws://{HOST}"
,blnSocketConnected, socket;
$(document).ready(function() {
var svrinfo = $("#svrinfo");
//Show the loading image whilst processing
$("#loading").show();
if ( !svrinfo ) {
alert("Cannot find tag 'svrinfo' in document!");
}
//Install timer to maintain socket connection
setInterval(function() {
try{
if ( !socket ) {
socket = io.connect(strSocketServer);
if ( socket ) {
socket.on(SCKMSG_CONNECT, function() {
//Connected!
});
socket.on(SCKMSG_DISCONNECT, function() {
//Disconnected!
});
socket.on(SCKMSG_LIST_CMPY, function(aryCompanies) {
//People list
var objCompanies = $('#cmpy');
if ( aryCompanies && aryCompanies.length ) {
for( var c in aryCompanies ) {
var objCompany = aryCompanies[c];
//What controls are available in the DOM?
if ( objCompanies && objCompanies.length ) {
$(objCompanies).append("<option value='" + objCompany['ckey']
+ "'>" + objCompany['n'] + "</option>");
}
}
//Hide the processing overlay
$("#loading").hide();
}
showContent();
});
}
}
if ( blnSocketConnected != undefined
&& (!socket || socket.disconnected) ) {
delete blnSocketConnected;
}
if ( !socket ) {
$(svrinfo).text("Cannot create socket!");
} else if ( !socket.connected ) {
if ( socket.disconnected ) {
$(svrinfo).text("Server has gone away!");
} else {
$(svrinfo).text("Connecting to server: " + strSocketServer);
}
} else {
$(svrinfo).text("Connected to server: " + strSocketServer);
}
if ( socket && blnSocketConnected != socket.connected ) {
$(svrinfo).show();
blnSocketConnected = socket.connected;
if ( blnSocketConnected ) {
//Hide the server status message
$(svrinfo).hide();
//Request people list
socket.emit(SCKMSG_LIST_REQCMPY);
}
}
} catch(ex) {
}
}, 500);
});
// -->
</script>
</head><body><div id = "svrinfo"></div>{CONTENT}<footer>{FOOTER}</footer><img id = "loading" src = "/images/loading.gif" width = "250" height = "70"/></body></html>
Мои определения макросов:
//PM = Page Macro
,PM_COMPANY = "{COMPANY}"
,PM_CONTENT = "{CONTENT}"
,PM_FOOTER = "{FOOTER}"
,PM_HEADER = "{HEADER}"
,PM_HOST = "{HOST}"
,PM_LAST_FAILED_LOGIN = "{dtLFLOGIN}"
,PM_LOGO_IMG = "{LOGO_IMG}"
,PM_LOGO_IMG_ALT = "{LOGO_IMG_ALT}"
,PM_LOGO_IMG_HEIGHT = "{LOGO_IMG_HEIGHT}"
,PM_LOGO_IMG_WIDTH = "{LOGO_IMG_WIDTH}"
,PM_PREFS = "{PREFS}"
,PM_UID = "{UID}"
Пример логики замены:
strPage = strPage.replace(consts.PM_HOST, strHost);
Однако это просто не работает... Я пробовал вводить escape-коды вокруг { и }, без разницы.
Я только что добавил в консоль дополнительные отчеты об отладке, после запуска они показывают:
L183 before replace strPage.indexOf({HOST}): 2585
L185 after replace strPage.indexOf({HOST}): -1
L195 before replace strPage.indexOf({COMPANY}): -1
L197 after replace strPage.indexOf({COMPANY}): -1
L218 before replace strPage.indexOf({PREFS}): -1
L220 after replace strPage.indexOf({PREFS}): -1
L243 before replace strPage.indexOf({CONTENT}): 4833
L245 after replace strPage.indexOf({CONTENT}): 9709
L299 before replace strPage.indexOf({HEADER}): -1
L301 after replace strPage.indexOf({HEADER}): -1
L306 before replace strPage.indexOf({FOOTER}): 9726
L308 after replace strPage.indexOf({FOOTER}): 9943
Каждая строка выше содержит оператор замены, некоторые из них, например COMPANY, PREFS и HEADER, возвращают -1, поскольку их нет в содержимом. Почему после замены обнаруживаются CONTENT и FOOTER?
[Править2] Новая функция, спасибо Энди:
function replaceMacro(strContent, cstrMacro, strReplacement) {
if ( !(typeof strContent == "string"
&& typeof strContent.length == "number"
&& strContent.length > 0
&& typeof cstrMacro == "string"
&& typeof cstrMacro.length == "number"
&& cstrMacro.length > 0
&& typeof strReplacement == "string"
&& typeof strReplacement.length == "number") ) {
return strContent;
}
let strUpdated = strContent;
const cRegEx = new RegExp(cstrMacro, 'g');
console.info(consts.RED + "L177 replaceMacro, searching for " + cstrMacro + ": " + String(strContent.indexOf(cstrMacro)) + consts.RESET); //HACK
strUpdated = strUpdated.replaceAll(cRegEx, strReplacement);
console.info(consts.RED + "L179 replaceMacro, searching for " + cstrMacro + ": " + String(strUpdated.indexOf(cstrMacro)) + consts.RESET); //HACK
return strUpdated;
}
Гораздо лучше, но все равно находит {CONTENT} после замены. Пример вызова, который все еще терпит неудачу:
strPage = replaceMacro(strPage, consts.PM_CONTENT, strContent);
Где PM_CONTENT содержит «{CONTENT}», а strContent содержит HTML-код, которым нужно заменить макрос.
@Энди, я правда не знаю, в чем дело, я попробовал несколько примеров и просмотрел типы. Может ли это быть связано с размером strContent, который в моем случае составляет 4950 байт. Мне не нужна «{замена}», я определил множество макросов, каждый из которых заключен в {}, но, похоже, он не может заменить ни один из них.
Попытка воспроизвести вашу проблему с помощью простого var strContent = "foo {subject} bar"; var strNew = strContent.replace("{subject}", "replacement"); console.info( strNew ); показывает, что вам определенно нужно показать полный фрагмент, который предположительно не работает, поскольку представленный фрагмент, похоже, работает так, как ожидалось.
Есть ли несколько экземпляров {subject} в одной строке? Если да, то вам понадобится replaceAll
Когда вы это сделаете replace("/{/gsubject/}/g", "replacement"), каков ваш ожидаемый результат? Вам все еще нужно сохранять фигурные скобки в строке, чтобы просто заменить слово?
Нет, мне не нужны фигурные скобки, а только заменяющий контент.



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


Не могли бы вы привести минимальный пример, где мы видим, что что-то идет не так? ИМХО, это просто работает.
let strContent = "The subject is {subject}"
let strNew = strContent.replace("{subject}", "replacement");
console.info(strNew)Вы можете использовать позитивный просмотр вперед и позитивный просмотр назад.
const strContent = 'subject {subject}'
const strNew = strContent.replace(/(?< = {)subject(?=})/, "replacement");
console.info(strNew)Также
"/{/gsubject/}/g"
это не регулярное выражение
Это регулярное выражение:
/{subject}/g
Регулярное выражение начинается с /, а не с "
Пожалуйста, ознакомьтесь с изменениями к вопросу, все еще борясь с этим.
Возможно, вам не хватает того, как использовать фактическое слово из макроса в регулярном выражении. Вы можете сделать это с помощью конструктора new RegExp.
Например: new RegExp(`{${obj.subject}}`, 'g'), о котором я подробно рассказал ниже. Примечание. Для определения субъектов/замен вместо макроса я использовал массив объектов.
// The text
const text = '{HOST} blah blah blah {CONTENT} blah blah {PAGE}'
// An array of objects containing the subject and replacement values
const mapping = [
{ subject: 'HOST', replacement: '10.4.1.13' },
{ subject: 'CONTENT', replacement: 'This is content' },
{ subject: 'PAGE', replacement: 'Page 1' },
];
// A function that accepts the text and the mapping object
function doReplace(text, mapping) {
let updated = text;
// Loop over the mapping object and for each object...
for (const obj of mapping) {
// ...take the subject value and add it to a template string
// in a regex constructor - "g" sets the global for the constructor
const regex = new RegExp(`{${obj.subject}}`, 'g');
// Use that regex in your replace/replaceAll method, using
// the replacement value from the object
updated = updated.replaceAll(regex, obj.replacement);
}
return updated;
}
console.info(doReplace(text, mapping));Дополнительная документация
Судя по данным вашего журнала, это работает. В некоторых случаях после замены строка больше не находится (-1), поскольку было заменено ее единственное вхождение. В других случаях он находится в новом месте позже в строке, поскольку он существует несколько раз, а первое вхождение только что было заменено.
Может быть, проблема в том, что вы ожидаете, что он заменит все вхождения? В этом случае вам нужно использовать replaceAll вместо replace, если вы используете строку в качестве аргумента иглы:
var strNew = strContent.replaceAll("{subject}", "replacement");
Или используйте регулярное выражение с модификатором g (глобальным):
var strNew = strContent.replace(/\{subject\}/g, "replacement");
Почему бы просто не
var strNew = strContent.replace("{subject}", "{replacement}");?