JavaScript replace()如果在startIndex和endIndex之间找到字符串as substring()

时间:2017-09-18 15:10:45

标签: javascript jquery

我的DOM中有一些HTML,我想在其中替换一些字符串,但前提是它尚未被替换或者不是TAG。

所有这些都基于一个包含我想要查找的字符串的数组以及我想要替换它的新字符串。

正在进行的工作:https://jsfiddle.net/u2Lyaab1/23/

更新:HTML标记只是为了简化,在示例代码中使用UL编写,但它可以包含不同的标记,事件不同的嵌套级别

基本上desiredReplcement工作得很好(除了它也在标签中查找),但我希望在DOM上发生这种情况,而不是新字符串,因为我想在DOM中维护任何其他HTML标记。 / p>

var list = [{
    original: 'This is',
    new: 'New this is'
  },
  {
    original: 'A list',
    new: 'New A list'
  },
  {
    original: 'And I want',
    new: 'New And I want'
  },
  {
    original: 'To wrap',
    new: 'New To wrap'
  },
  {
    original: 'li',
    new: 'bold'
  },
  {
    original: 'This',
    new: 'New This'
  },
  {
    original: 'strong',
    new: 'bold'
  },  {
original: 'This is another random tag',
new: 'This is another random tag that should be bold'
  }

];


var div = $('.wrap');
var htmlString = div.html();
var index = 0;
list.forEach(function(item, index) {

  console.log(index + ' Should replace: "' + item.original + '" with "' + item.new + '"');

  //I know that there is something here, but not sure what
  index = htmlString.indexOf(item.original);
  var expressionLength = index + item.original.length;
  var substring = htmlString.substring(index, expressionLength);
  var desiredReplcement = substring.replace(item.original, '<strong>' + item.new + '</strong>');
  console.log('index', index);
  console.log('substring', substring);
  console.log('desiredReplcement', desiredReplcement);

  //Current implementation in replace looks in the full div, but I just want to replace in the substring mathced above;
  var replacement = '<strong>' + item.new + '</strong>';
  var newHTML = div.html().replace(item.original, replacement);
  div.html(newHTML);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">
  <ul>
    <li>This is</li>
    <li>A list</li>
    <li>And I want</li>
    <li>This should not be bold</li>
    <li>To wrap</li>
    <li>This</li>
    <li>strong</li>
    <li>li</li>
  </ul>
<span><p><em>This is another random tag</em></p></span>
</div>

4 个答案:

答案 0 :(得分:3)

您的div变量引用了<div class="wrap">...</div>,因此您的htmlString值是一组html标记而不是字符串。

这是您的代码无法正常工作的主要原因。

因此我改写了你的实现。

var list = [
  {
    original: 'This is',
    new: 'New this is'
  },
  {
    original: 'A list',
    new: 'New A list'
  },
  {
    original: 'And I want',
    new: 'New And I want'
  },
  {
    original: 'To wrap',
    new: 'New To wrap'
  },
  {
    original: 'li',
    new: 'bold'
  },
  {
    original: 'This',
    new: 'New This'
  },
  {
    original: 'strong',
    new: 'bold'
  }
  
];

var div = document.getElementsByClassName('wrap')[0].getElementsByTagName('li');  // Getting all <li> elements within <div class="wrap">

Array.prototype.forEach.call(div, function(li, x){  // Borrowing Array's forEach method to be used on HTMLCollection

    list.forEach(function(value, i){                // Looping through list
        if (value.original === li.innerHTML)        // if list[i]['original'] === li[x].innerHTML
            li.innerHTML = '<strong>' + value.new + '</strong>';
            
    });
    
    
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">
  <ul>
     <li>This is</li>
     <li>A list</li>
     <li>And I want</li>
     <li>This should not be bold</li>
     <li>To wrap</li>
     <li>This</li>
     <li>strong</li>
     <li>li</li>
  </ul>
</div>

答案 1 :(得分:1)

以下代码不会替换标记,只会对一个文本节点进行一次替换(如果有匹配)。它以递归的方式查看整个结构并检查元素的文本。(并使用您在问题中描述的相同列表)

要求:

  1. 仅在完全匹配的情况下替换文字=&gt;使用===而不是indexOf

  2. 仅替换一次文字=&gt;使用后从列表中删除项目

    var div = $('.wrap');
    
    function substitute(htmlElement, substituteStrings){
      var childrenElements = htmlElement.children;
      if(childrenElements.length !== 0){
        for (let i=0;i<childrenElements.length;i++){
            substitute(childrenElements[i], substituteStrings);
        }
      } else {
        var htmlString = htmlElement.innerText;
        substituteStrings.some(function(item){
            if(htmlString == item.original){
                htmlElement.innerHTML = htmlString.replace(item.original, '<strong>' + item.new + '</strong>');
                substituteStrings.splice(index,1);
                return true;
            }
        });
      }
    }
    substitute(div[0],list);
    

答案 2 :(得分:1)

我不认为jQuery是必要的。

首先,您要检索容器,在您的情况下将是.wrap div。

var container = document.querySelector('.wrap');

然后你想要创建一个递归函数,它将遍历一个数组来搜索和替换提供的数据。

function replacement(containers, data){

    if(!data || !data.length)
        return;

    for(let i=0; i<containers.length; i++){

        var container = containers[i];

        // Trigger the recursion on the childrens of the current container
        if(container.children.length)
            replacement(container.children, data);

        // Perform the replacement on the actual container
        for(let j=0; j<data.length; j++){
            var index = container.textContent.indexOf(data[j].original);

            // Data not found
            if(index === -1)
                continue;

            // Remove the data from the list
            var replace = data.splice(j, 1)[0];
            container.innerHTML = container.innerHTML.replace(replace.original, '<strong>' + replace.new + '</strong>');

            // Lower the j by 1 since the data array length has been updated
            j--;

            // Only want to perform one rule
            break;

        }
    }
}

演示:https://jsfiddle.net/u2Lyaab1/25/

答案 3 :(得分:1)

基本思想是使用递归来搜索父节点中的每个嵌套节点。

我的答案(部分答案)与Zsolt V's的结果相同,但不太优雅。

Zsolt V检查了子节点,因此可以使用HTML标签处理innerHTML。另一方面,我检查了一个节点是否是一个textNode,并使用DOM(纯DOM解决方案)和节点的textContent属性构建了替换节点。

var list = [{
    original: 'This is',
    new: 'New this is'
  }, {
    original: 'A list',
    new: 'New A list'
  }, {
    original: 'And I want',
    new: 'New And I want'
  }, {
    original: 'To wrap',
    new: 'New To wrap'
  }, {
    original: 'li',
    new: 'bold'
  }, {
    original: 'This',
    new: 'New This'
  }, {
    original: 'strong',
    new: 'bold'
  }, {
    original: 'This is another random tag',
    new: 'This is another random tag that should be bold'
  }

];


//I want for each expression in this array, to find that expression in array, replace-it and make-it bold with a <strong> tag.

var div = document.getElementsByClassName("wrap")[0];

function processNode(node) {
  if (node.nodeName === "#text") {
    list.forEach(function(item, index) {
      if (node.parentNode && node.textContent.indexOf(item.original) > -1) {
        //node.textContent = node.textContent.replace(item.original, item.new);

        let untouched = node.textContent.split(item.original);
        console.log(untouched);
        for (let i = untouched.length - 1; i > 0; i--) {
          untouched.splice(i, 0, item.new);
        }
        console.log(untouched);
        for (let i = 0, l = untouched.length; i < l; i++) {
          let newNode = i % 2 === 0 ? document.createTextNode("") : document.createElement("strong");
          newNode.textContent = untouched[i];
          node.parentNode.appendChild(newNode);
        }
        node.parentNode.removeChild(node);
      }
    })
  } else {
    node.childNodes.forEach(function(child, index) {
      processNode(child);
    })
  }
}

processNode(div)

JSFiddle(部分答案)

你在Zsolt V回答的评论中写道:

  

但正如您所看到的,最后一句被替换为不同于列表中的预期

然而,问题不在于代码,而在于list数组的排序。问题是您有替换工作在彼此之内,即使用list[7]代理list[0]

这是另一个随机标记”(list[7]之前)

- &GT; “新增另一个随机标记”(list[7]后应用更改后list[0]

你需要注意顺序。

事实上,我将list数组中的最后一项移到了顶部,结果就像你要求的那样。

var list = [{
    original: 'This is another random tag',
    new: 'This is another random tag that should be bold'
  }, {
    original: 'This is',
    new: 'New this is'
  }, {
    original: 'A list',
    new: 'New A list'
  }, {
    original: 'And I want',
    new: 'New And I want'
  }, {
    original: 'To wrap',
    new: 'New To wrap'
  }, {
    original: 'li',
    new: 'bold'
  }, {
    original: 'This',
    new: 'New This'
  }, {
    original: 'strong',
    new: 'bold'
  }

];

JSFiddle(完整答案)