skip to Main Content

I can replace a normal string using:

var strNew = strContent.replace("subject", "replacement");

The above works find, however:

var strNew = strContent.replace("{subject}", "replacement");

Doesn’t work, is there something I need to do?

I’ve tried:

var strNew = strContent.replace("/{/gsubject/}/g", "replacement");

Didn’t work either…

[Edit] Something is very wrong, I’ve added more debug, BTW, this is run by Node.js v21.7.1 on Windows 10.

I read a HTML page from MariaDB, this is read into a string:

<!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>

My macro definitions:

//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}"

An example of the replace logic:

strPage = strPage.replace(consts.PM_HOST, strHost);

However it just isn’t working…I’ve tried putting in escape codes around { and }, no difference.

I’ve just added more debug reporting to the console, after running it shows:

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

Each line above is around a replace statement, some like the COMPANY, PREFS and HEADER will return -1 because these aren’t present in the content, why is CONTENT and FOOTER found after the replace?

[Edit2] New function, thank you to Andy:

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.log(consts.RED + "L177 replaceMacro, searching for " + cstrMacro + ": " + String(strContent.indexOf(cstrMacro)) + consts.RESET);    //HACK        
    strUpdated = strUpdated.replaceAll(cRegEx, strReplacement);
console.log(consts.RED + "L179 replaceMacro, searching for " + cstrMacro + ": " + String(strUpdated.indexOf(cstrMacro)) + consts.RESET);    //HACK        
    return strUpdated;
}

Much better but still finds {CONTENT} after the replace. Example of the call that still fails:

strPage = replaceMacro(strPage, consts.PM_CONTENT, strContent);

Where PM_CONTENT contains "{CONTENT}" and strContent contains the HTML to replace the macro with.

4

Answers


  1. Could you provide a minimal example where we can see it go wrong? IMO this just works.

    let strContent = "The subject is {subject}"
    let strNew = strContent.replace("{subject}", "replacement");
    
    console.log(strNew)
    Login or Signup to reply.
  2. You can use positive lookahead and positive lookbehind

    const strContent = 'subject {subject}'
    const strNew = strContent.replace(/(?<={)subject(?=})/, "replacement");
    console.log(strNew)

    Also

    "/{/gsubject/}/g"
    

    is not a regex

    This is a regex:

    /{subject}/g
    

    Regex starts with / and not "

    Login or Signup to reply.
  3. It’s possible that the part you’re missing is how to use an actual word from the macro in the regular express. You can do that by using the new RegExp constructor.

    For example: new RegExp(`{${obj.subject}}`, 'g') which I’ve elaborated on below. Note: I’ve used an array of objects to defined the subjects/replacements instead of a macro.

    // 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.log(doReplace(text, mapping));

    Additional documentation

    Login or Signup to reply.
  4. It seems that it does work, according to your log output. In some cases the string is no longer found (-1) after replacing, because its only occurrence was replaced. In other cases it is found at a new location later in the string, because it exists multiple times and the first occurrence just got replaced.

    Maybe the issue is that you expect it to replace all occurrences? In this case you need to use replaceAll instead of replace if you use a string as needle argument:

    var strNew = strContent.replaceAll("{subject}", "replacement");
    

    Or, use a regex with the g (global) modifier:

    var strNew = strContent.replace(/{subject}/g, "replacement");
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search