最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript Replace - Dynamic Value of Replacement - Stack Overflow

programmeradmin3浏览0评论

I have a template in a String and I want to replace a few of the placeholders with the values that I have in another string. For every placeholder that I replace, I also want to insert a break tag.

For eg if #ADDRESS2# is found in the template, I am using the following code to replace all its occurrences with value in string val.address2.

    template_html = template_html.replace(/#ADDRESS2#/g, '<br />'+ val.address_2);

However there are scenarios when the string val.address2 is empty. In that case, I do not want to insert the break tag.

So I changed my code as follows

    if( val.address_2.length > 0 ) {
        template_html = template_html.replace(/#ADDRESS2#/g, '<br />'+ val.address_2);
    } else {
        template_html = template_html.replace(/#ADDRESS2#/g, '');
    }

Is there a better way to write the above code as I have multiple Placeholders and for each Placeholder I have to write the code 2 times.

I have a template in a String and I want to replace a few of the placeholders with the values that I have in another string. For every placeholder that I replace, I also want to insert a break tag.

For eg if #ADDRESS2# is found in the template, I am using the following code to replace all its occurrences with value in string val.address2.

    template_html = template_html.replace(/#ADDRESS2#/g, '<br />'+ val.address_2);

However there are scenarios when the string val.address2 is empty. In that case, I do not want to insert the break tag.

So I changed my code as follows

    if( val.address_2.length > 0 ) {
        template_html = template_html.replace(/#ADDRESS2#/g, '<br />'+ val.address_2);
    } else {
        template_html = template_html.replace(/#ADDRESS2#/g, '');
    }

Is there a better way to write the above code as I have multiple Placeholders and for each Placeholder I have to write the code 2 times.

Share Improve this question edited Aug 13, 2019 at 14:21 Cerbrus 72.9k19 gold badges136 silver badges150 bronze badges asked Aug 13, 2019 at 13:58 ascsoftwascsoftw 3,4762 gold badges16 silver badges23 bronze badges 5
  • 2 Since jQuery is (primarily) a DOM manipulation library, it's not really relevant here. I've removed that tag. – Cerbrus Commented Aug 13, 2019 at 14:22
  • why not use same template strings in the text and in the objects. it makes it easier to just replace with the same string. – Nina Scholz Commented Aug 13, 2019 at 14:22
  • 1 Can you show more of those "multiple Placeholders" that you have? E.g. are they all quite regular or not, and how do they relate to the property names used for the replacement? – Peter B Commented Aug 13, 2019 at 14:40
  • @nina yes, I can change the template to have same name as string. – ascsoftw Commented Aug 13, 2019 at 15:03
  • @peter other vplaceholders are like City, State, zip. I can make the placeholder name same as object if that helps – ascsoftw Commented Aug 13, 2019 at 15:05
Add a ment  | 

7 Answers 7

Reset to default 13

Use a regex replacement, to which you pass a function.

That function will get the replacement keys as input, and depending on if there's a replacement available, it will insert a empty string, or the replacement with a linebreak:

const template = "#foo# this bla bla #bar# but #baz# and stuff";

const replacements = {
  foo: "test",
  bar: "",
  baz: "not empty"
};

const result = template.replace(/#([^#]+)#/g, (match, key) => {
  // If there's a replacement for the key, return that replacement with a `<br />`. Otherwise, return a empty string.
  return replacements[key] !== undefined
    ? "<br />" + replacements[key]
    : "";
});

console.log("template:", template);
console.log("result:", result);

The only "gotcha" here is that the keys in the template string have to match the keys in your replacements object. That's not necessarily a bad thing, though, as it would make it slightly more intuitive if you'd look back at your code later on.

The regex may look intimidating, but it's really quite simple:

/#([^#]+)#/g

  • /: The start of the regex,
  • #: Literally the # character,
  • (: The start of a capturing group,
  • [^#]+ Any character that isn't a #. The + makes sure it matches as many as possible,
  • ): The end of a capturing group,
  • #: Literally the # character,
  • /g: The end of the regex. g is the global flag, so it doesn't stop at the first result.

The capturing group basically tells the regex to group everything that's between the brackets. The groups are then returned individually.

Perhaps you meant this?

var val = {
  "address_1": "Address 1",
  "address_2": "",
  "address_10": "Address 10",
}  
var template_html = `My address is #ADDRESS1# delivery address is #ADDRESS2# and billing is #ADDRESS10#`
template_html = template_html.replace(/#ADDRESS(\d+)#/g, function(addr, num) { 
  var str = val["address_"+num]; return str?str+"<br/>":""
})
console.log(template_html)

If the same logic should be applied for multiple address fields, then you might benefit from a helper function:

template_html = template_html
    .replace(/#CITY1#/g, PrefixBrIfNotEmpty(val.city_1))
    .replace(/#CITY2#/g, PrefixBrIfNotEmpty(val.city_2))
    .replace(/#CITY3#/g, PrefixBrIfNotEmpty(val.city_3))
    .replace(/#ADDRESS1#/g, PrefixBrIfNotEmpty(val.address_1))
    .replace(/#ADDRESS2#/g, PrefixBrIfNotEmpty(val.address_2))
    .replace(/#ADDRESS3#/g, PrefixBrIfNotEmpty(val.address_3));

function PrefixBrIfNotEmpty(str) {
    return str ? '<br />' + str : '';
}

You can use ternary operator (empty string evaluates to false)

template_html = template_html.replace(/#ADDRESS2#/g, val.address_2 ? '<br />'+ val.address_2 : '');

The simplest change is to use the ternary operator like this:

template_html = template_html.replace(/#ADDRESS2#/g, ( val.address_2.length > 0 ) ? '<br />'+ val.address_2 : '');

Still not particularly elegant but a bit shorter than the original.

You could take the value with a check.

template_html = template_html.replace(
    /#ADDRESS2#/g,
    val.address_2 && '<br />' + val.address_2
);

For more than one placeholder, you could take a dynamic approach and use same pattern for the search and replacements.

var val = { address_2: 'foo', country_1: 'bar' }
    template_html = 'Address: #ADDRESS2#\nCountry: #COUNTRY1#\nnothing: #NOTHING#'

template_html = template_html.replace(
    /#([^#]+)#/g,
    (_, group) => {
        var key = group.match(/^(\D+)(\d*)$/).slice(1).map(s => s.toLowerCase()).join('_');

        return (val[key] || '') && '<br />' + val[key];
     }
);
console.log(template_html);

For getting a smarter replacement, yoou could take the idea of same strings as tempate and for getting the data from an object. In this case, take the replacement value and take this as key for the object or take an empty string for unknown values.

var val = { ADDRESS2: 'foo', COUNTRY1: 'bar' }
    template_html = 'Address: #ADDRESS2#\nCountry: #COUNTRY1#\nnothing: #NOTHING#'

template_html = template_html.replace(
    /#([^#]+)#/g,
    (_, key) => (val[key] || '') && '<br />' + val[key]
);
console.log(template_html);

You mean, something like this:

template_html = template_html.replace(/#ADDRESS(\d+)#/g, function(address, number) {
    return val.hasOwnProperty('address_' + number)
        ? '<br />' + val['address_' + number]
        : '';
};

You should use the val.hasOwnProperty just in case that val.['address_' + number] contains a value like 0, false, '', undefined, NaN or other falsy values.
It makes sure the value is displayed anyway, because an undefined isn't the same as not having the property at all.

It also avoids to get a value from the prototype, just in case.

This is based on mplungjan's answer.


If this is undesirable, and you only want to show strings, try this:

template_html = template_html.replace(/#ADDRESS(\d+)#/g, function(address, number) {
    return val.hasOwnProperty('address_' + number)
    && val['address_' + number].length
    && (
        (typeof val['address_' + number]) === 'string'
        || val['address_' + number] instanceof String
    )
        ? '<br />' + val['address_' + number]
        : '';
};

All of this checking ensures that it is a non-empty string (or String instance, because new String() returns a string object).
Checking if it is an instance of String prevents issues due to typeof new String() returning object.

Arrays and array-like objects have a length attributes (e.g.: jQuery instance, NodeList, {length: 1}, [0] and similars), but you dont want to show them as strings.

发布评论

评论列表(0)

  1. 暂无评论