字符串操作 JavaScript - 替换占位符

String manipulation JavaScript - replace placeholders

我有一个很长的字符串,我必须以特定的方式对其进行操作。该字符串可以包含其他子字符串,这会导致我的代码出现问题。出于这个原因,对字符串做任何事情之前,我用格式:[=15=]</code>、<code>、...、$n。我确定主字符串本身不包含字符 $ 但子字符串之一(或更多)可能是例如 "[=20=]".

现在的问题是:在 manipulation/formatting 主字符串之后,我需要再次用它们的实际值替换所有占位符。

为了方便,我将它们保存为这种格式:

// TypeScript
let substrings: { placeholderName: string; value: string }[];

但是在做:

// JavaScript
let mainString1 = "main string [=12=] ";
let mainString2 = "main string [=12=] ";

let substrings = [
  { placeholderName: "[=12=]", value: "test1 " },
  { placeholderName: "", value: "test2" }
];

for (const substr of substrings) {
  mainString1 = mainString1.replace(substr.placeholderName, substr.value);
  mainString2 = mainString2.replaceAll(substr.placeholderName, substr.value);
}

console.log(mainString1); // expected result: "main string test1 test2 "
console.log(mainString2); // expected result: "main string test1 test2 test2"

// wanted result: "main string test1  test2"

不是一个选项,因为子字符串可能包括$x,这会替换错误的东西(通过.replace().replaceAll()).

获取子字符串是用正则表达式存档的,也许正则表达式也能帮上忙?虽然我无法控制子字符串中保存的内容...

这可能不是最有效的代码。但这是我用评论制作的功能。

注意:请小心,因为如果将相同的占位符放在其自身内部,则会产生无限循环。例如:

{ placeholderName: "", value: "test2 " }

let mainString1 = "main string [=11=] ";
let mainString2 = "main string [=11=] ";

let substrings = [{
    placeholderName: "[=11=]",
    value: "test1 "
  },
  {
    placeholderName: "",
    value: "test2"
  },
];

function replacePlaceHolders(mainString, substrings) {
  let replacedString = mainString

  //We will find every placeHolder, the followin line wil return and array with all of them. Ex: ['', $n']
  let placeholders = replacedString.match(/$[0-9]*/gm)

  //while there is some place holder to replace
  while (placeholders !== null && placeholders.length > 0) {
    //We will iterate for each placeholder
    placeholders.forEach(placeholder => {
      //extrac the value to replace
      let value = substrings.filter(x => x.placeholderName === placeholder)[0].value
      //replace it
      replacedString = replacedString.replace(placeholder, value)
    })
    //and finally see if there is any new placeHolder inserted in the replace. If there is something the loop will start again.
    placeholders = replacedString.match(/$[0-9]*/gm)
  }

  return replacedString
}

console.log(replacePlaceHolders(mainString1, substrings))
console.log(replacePlaceHolders(mainString2, substrings))

编辑:

好的...我想我现在明白了您的问题...您不想替换值中的 placeHoldersLike 字符串。

此版本的代码应按预期工作,您不必担心这里的无限循环。但是,请注意您的占位符,“$”是正则表达式中的保留字符,它们更多是您应该转义的。我假设您所有的占位符都将像“$1”、“$2”等。如果不是,您应该编辑 regexPlaceholder 函数来包装和转义该字符。

let mainString1 = "main string [=12=] ";
let mainString2 = "main string [=12=]  ";

let substrings = [
    { placeholderName: "[=12=]", value: " test1  " },
    { placeholderName: "", value: "test2 " },
    { placeholderName: "", value: "test3" },

];

function replacePlaceHolders(mainString, substrings) {

    //You will need to escape the $ characters or maybe even others depending of how you made your placeholders
    function regexPlaceholder(p) {
        return new RegExp('\' + p, "gm")
    }

    let replacedString = mainString
  //We will find every placeHolder, the followin line wil return and array with all of them. Ex: ['', $n']
    let placeholders = replacedString.match(/$[0-9]*/gm)
    //if there is any placeHolder to replace
    if (placeholders !== null && placeholders.length > 0) {

        //we will declare some variable to check if the values had something inside that can be 
        //mistaken for a placeHolder. 
        //We will store how many of them have we changed and replace them back at the end
        let replacedplaceholdersInValues = []
        let indexofReplacedValue = 0

        placeholders.forEach(placeholder => {
            //extrac the value to replace
            let value = substrings.filter(x => x.placeholderName === placeholder)[0].value

            //find if the value had a posible placeholder inside
            let placeholdersInValues = value.match(/$[0-9]*/gm)
            if (placeholdersInValues !== null && placeholdersInValues.length > 0) {
                placeholdersInValues.forEach(placeholdersInValue => {
                    //if there are, we will replace them with another mark, so our primary function wont change them
                    value = value.replace(regexPlaceholder(placeholdersInValue), "<markToReplace" + indexofReplacedValue + ">")
                    //and store every change to make a rollback later
                    replacedplaceholdersInValues.push({
                        placeholderName: placeholdersInValue,
                        value: "<markToReplace" + indexofReplacedValue + ">"
                    })

                })
                indexofReplacedValue++
            }
            //replace the actual placeholders
            replacedString = replacedString.replace(regexPlaceholder(placeholder), value)
        })

        //if there was some placeholderlike inside the values, we change them back to normal
        if (replacedplaceholdersInValues.length > 0) {
            replacedplaceholdersInValues.forEach(replaced => {
                replacedString = replacedString.replace(replaced.value, replaced.placeholderName)
            })
        }
    }

    return replacedString
}

console.log(replacePlaceHolders(mainString1, substrings))
console.log(replacePlaceHolders(mainString2, substrings))

关键是选择一个占位符,在主串和子串中都不可能。我的技巧是使用 non-printable 个字符作为占位符。我最喜欢的是 NUL 字符 (0x00),因为大多数其他人不会使用它,因为 C/C++ 认为它是字符串的结尾。 Javascript 然而足够强大以处理包含 NUL 的字符串(编码为 un​​icode \0000):

let mainString1 = "main string [=10=]-0 [=10=]-1";
let mainString2 = "main string [=10=]-0 [=10=]-1";

let substrings = [
  { placeholderName: "[=10=]-0", value: "test1 " },
  { placeholderName: "[=10=]-1", value: "test2" }
];

其余代码无需更改。

请注意,我使用 - 字符来防止 javascript 将您的数字 01 解释为八进制 [=16=] 的一部分.

如果您像大多数程序员一样厌恶 [=16=],那么您可以使用任何其他 non-printing 字符,例如 </code>(标题开始)、<code>007(使您的终端发出铃声的角色 - 还有 James Bond) 等

如果您确定所有占位符都将遵循 $x 格式,我会使用带有回调的 .replace() 方法:

const result = mainString1.replace(
  /$\d+/g,
  placeholder => substrings.find(
    substring => substring.placeholderName === placeholder
  )?.value ?? placeholder
);

// result is "main string test1  test2"