使用正则表达式从列表中替换带有标记的文本

时间:2017-05-06 08:47:56

标签: javascript regex

我试图使用正则表达式在React.js中编写一个简单的文本替换器,但我无法绕过它。

所以我有一份令牌列表及其相应的替换文字。我还有一个文本区域,其中包含用户编写的文本。每当一个单词缠绕{}时,文本将被替换为相应标记的替换文本。

例如,如果我在textarea中的某处有一个{example},我将不得不检查我的令牌列表,看看我是否在列表中有值示例,并将{example}替换为列表的替换值。

我现在正在做的是使用以下方法检查我的textarea中是否有任何匹配:

let regEx = /\{[a-zA-Z_][a-zA-Z0-9_]*\}/;
inputText.match(regEx);

结果我得到了一个索引和输入,但是如何用替换文本替换匹配的文本?我尝试使用替换功能,但不知怎的,我无法理解如何使用它。

这是我的过滤功能,您可以查看:

this.filterText = () => {
  //check if we have text in Input text area
  if (this.state.inputText) {
    let regEx = /\{[a-zA-Z_][a-zA-Z0-9_]*\}/;
    let inputText = this.state.inputText;
    this.state.data.forEach((token, index) => {
      let match = inputText.match(regEx);
      if (match) {
        console.log('match:', match);
        //should replace matched text with replacement text
        inputText.replace(regEx, this.state.data[index].replacementText);
      }
    });
  }
}

3 个答案:

答案 0 :(得分:1)

这是一个简单的vanilla js解决方案。例如,在textarea中的任何地方输入我喜欢{make} stuffs {make}应替换为create

修改

已经进行了更改以支持递归替换。

现在可以在替换字符串中包含一些{token}

代码也会阻止循环调用。

尝试键入{hello}{circular}以确保其按您希望的方式运行。

<强>段

document.addEventListener("DOMContentLoaded", function() {
  buildResult();
});

let tokens = {
  "civility": "Mr",
  "dummy": "really dummy",
  "foo": "bar",
  "firstName": "Marty",
  "lastName": "McFly",
  "hello": "Hello {firstName} {lastName}",
  "circular": "Hello {circular} {firstName} {lastName}",
  "make": "create",

}

function buildResult() {
  let text = document.getElementById('userInput').value;
  let result = replaceTokens(text);
  document.getElementById('result').innerHTML = result;
}

function replaceTokens(text, replacementStack) {
  // const re = /{([^}]+)}/g; // match anything but a `}` between braces
  const re = /{[\w]*\}/g; // match initial regex

  let result = text;
  let textTokens = text.match(re);
  replacementStack = replacementStack || [];

  textTokens && textTokens.forEach(m => {
    let token = m.replace(/{|}/g, '');
    // Prevent circular replacement, token should not have already replaced
    if (replacementStack.indexOf(token) === -1) {
      // add token to replacement stack
      replacementStack.push(token);
      let replacement = tokens[token];
      if (replacement) {
        replacement = replaceTokens(replacement, replacementStack);
        result = result.replace(m, replacement);
      }
    }
  });

  return result;
}
<!DOCTYPE html>
<html>
<head>
  <title></title>
  <script src="script.js"></script>
  <style>
    label { display: block; font-weight: bold; }
    textarea { width: 600px; height: 150px; }
  </style>
</head>
<body>

  <label>Enter text</label>
  <textarea id="userInput" onkeyup="buildResult()">Lorem Ipsum is simply {dummy} text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to {make} a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</textarea>

  <label>Result</label>
  <div id="result"></div>

</body>
</html>

答案 1 :(得分:0)

它不起作用,因为替换函数中的regEx必须正是您要替换的内容(在这种情况下是令牌本身)。

试试这个: https://jsfiddle.net/KlaussU/f4mxa3vw/2/

<button onclick="replaceText('tokenX replaced: {tokenX}')">Try it</button>
<p id="demo"></p>

<script>
var replacementText = {
    "tokenX": "tokenXReplaced",
    "tokenY": "tokenYReplaced",
    "tokenZ": "tokenZReplaced"
};

function replaceText(text) {
    for(var rt in replacementText) {
        text = text.replace(new RegExp("{" + rt + "}"), replacementText[rt]);
    }
    document.getElementById("demo").innerHTML = text;
}
</script>

P.S你可能会发现这里接受的答案也很有用: Javascript Regex: How to put a variable inside a regular expression?

答案 2 :(得分:0)

您发布的代码从未指定replace的结果。我不确定data结构,但以下内容应与布局有所对应。

&#13;
&#13;
function foo(){
	this.state = {inputText:'this is a test that should {verb} both the first {noun} between {} and also the following {noun}s, but not {other} tags'};
  this.data = {verb:'replace', noun:'element'};
  this.filterText = () => !this.state.inputText || Object.keys(this.data).reduce((t,k)=>
  	t.replace(new RegExp('{' + k + '}','g'),this.data[k])
  	,this.state.inputText
  );
}

let f = new foo();console.log(f.filterText());
&#13;
&#13;
&#13;

想法是颠倒逻辑,而不是找到所有{}标签,而是使用标记作为源(这与我现在看到的Klaus&#39;答案相同)。 这里甚至不需要正则表达式进行替换,但它适用于g lobal flag