简体   繁体   English

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

[英]JavaScript replace() if string found between startIndex and endIndex as substring() does

I have some HTML in my DOM and I want to replace some strings in it, but only if that was not already replaced or that is not a TAG. 我的DOM中有一些HTML,我想在其中替换一些字符串,但前提是它尚未被替换或者不是TAG。

All that is based on an Array that contains the string I want to find and the new string I want this to be replace with. 所有这些都基于一个包含我想要找到的字符串的数组以及我想要替换它的新字符串。

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

UPDATE: The HTML markup is just for simplicity written with ULs in the sample code, BUT it can contain different tags, event different nesting levels 更新:HTML标记只是为了简化在示例代码中使用UL编写的,但它可以包含不同的标记,事件不同的嵌套级别

Basically the desiredReplcement works nice (except that it looks in tags too), but I want that to happen on the DOM, not the new string because I want to maintain any other HTML markup in the DOM. 基本上, desiredReplcement工作得很好(除了它也在标签中查找),但我希望在DOM上发生这种情况,而不是新字符串,因为我想在DOM中维护任何其他HTML标记。

SNIPPET : SNIPPET

 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> 

Your div variable is referencing <div class="wrap">...</div> , therefore your htmlString value is a group of html tags instead of string. 你的div变量引用<div class="wrap">...</div> ,因此你的htmlString值是一组html标签而不是字符串。

That is the main reason your code is not working as expected. 这是您的代码无法按预期工作的主要原因。

And therefore I rewrote your implementation. 因此我重写了你的实现。

 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> 

The following code will not replace tags and will do only one replacement for one text node (if there is any match). 以下代码不会替换标记,并且只对一个文本节点执行一次替换(如果有匹配)。 It looks through the whole structure in a recursive manner and checks the text of the elements.(and it uses the same list you described in your question) 它以递归方式查看整个结构并检查元素的文本。(它使用您在问题中描述的相同列表)

Requirements: 要求:

  1. Replace text just in case of exact match => use === instead of indexOf 在完全匹配=> use ===而不是indexOf的情况下替换文本

  2. Replace text only once => remove item from list after use 仅替换文本一次=>使用后从列表中删除项目

     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); 

I don't think that jQuery is necessary here. 我认为这里不需要jQuery。

First, you want to retrieve your container, which in your case will be the .wrap div. 首先,您要检索容器,在您的情况下将是.wrap div。

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

Then you want to create a recursive function that will loop through an array to search and replace the data provided. 然后,您需要创建一个递归函数,该函数将循环遍历数组以搜索和替换提供的数据。

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;

        }
    }
}

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

The basic idea is to use recursion to search through every nested node in the parent node. 基本思想是使用递归来搜索父节点中的每个嵌套节点。

My answer (partial answer) has the same results as Zsolt V's , but is a little less elegant. 我的答案(部分答案)与Zsolt V的结果相同,但不太优雅。

Zsolt V has checked child nodes, and it can therefore work with innerHTML by using HTML tags. Zsolt V检查了子节点,因此可以使用HTML标签处理innerHTML。 I on the other hand have checked if a node is a textNode, and have built the replacement nodes using the DOM (pure DOM solution) and nodes' textContent property. 另一方面,我检查了一个节点是否是一个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 (partial answer) JSFiddle (部分答案)

You write in the comments on Zsolt V's answer that: 你在Zsolt V的回答评论中写道:

but as you can see, the last sentence is replaced differently than the expected in the list 但正如您所看到的,最后一句被替换为与列表中的预期不同

However, the problem is not with the code, but with the ordering of the list array. 但是,问题不在于代码,而在于list数组的顺序。 The problem is that you have replacements that work within one another, ie acting on list[7] , with list[0] : 问题是你有一个在另一个内部工作的替换,即在list[0]上作用于list[7] list[0]

" This is another random tag" ( list[7] before) 这是另一个随机标签”(之前的list[7]

-> " New this is another random tag" ( list[7] after applying changes from list[0] ) - >“ 新增这是另一个随机标记”( list[7]后应用list[0]更改)

You need to be mindful of the ordering. 你需要注意订购。

In fact, I moved the last item in the list array to the top, and the results are as you've asked for. 事实上,我将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 (full answer) JSFiddle (完整答案)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM