Замена строки, как заменить строку, завернутую в {}?

Я могу заменить обычную строку, используя:

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-код, которым нужно заменить макрос.

Почему бы просто не var strNew = strContent.replace("{subject}", "{replacement}");?

Andy 25.03.2024 10:08

@Энди, я правда не знаю, в чем дело, я попробовал несколько примеров и просмотрел типы. Может ли это быть связано с размером strContent, который в моем случае составляет 4950 байт. Мне не нужна «{замена}», я определил множество макросов, каждый из которых заключен в {}, но, похоже, он не может заменить ни один из них.

SPlatten 25.03.2024 10:29

Попытка воспроизвести вашу проблему с помощью простого var strContent = "foo {subject} bar"; var strNew = strContent.replace("{subject}", "replacement"); console.info( strNew ); показывает, что вам определенно нужно показать полный фрагмент, который предположительно не работает, поскольку представленный фрагмент, похоже, работает так, как ожидалось.

Wiktor Zychla 25.03.2024 10:45

Есть ли несколько экземпляров {subject} в одной строке? Если да, то вам понадобится replaceAll

TiiJ7 25.03.2024 10:46

Когда вы это сделаете replace("/{/gsubject/}/g", "replacement"), каков ваш ожидаемый результат? Вам все еще нужно сохранять фигурные скобки в строке, чтобы просто заменить слово?

Andy 25.03.2024 10:48

Нет, мне не нужны фигурные скобки, а только заменяющий контент.

SPlatten 25.03.2024 12:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
6
90
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Не могли бы вы привести минимальный пример, где мы видим, что что-то идет не так? ИМХО, это просто работает.

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

Регулярное выражение начинается с /, а не с "

Пожалуйста, ознакомьтесь с изменениями к вопросу, все еще борясь с этим.

SPlatten 25.03.2024 10:59
Ответ принят как подходящий

Возможно, вам не хватает того, как использовать фактическое слово из макроса в регулярном выражении. Вы можете сделать это с помощью конструктора 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");

Другие вопросы по теме