Поиск и замена определенных текстовых символов в документе с помощью JS

Мне интересно, есть ли легкий способ использовать JavaScript или jQuery, чтобы вынюхивать определенный текстовый символ в документе; скажем и найдите все экземпляры этого символа. И затем! Напишите возможность заменить все экземпляры этого с помощью $.

Я нашел этот фрагмент для начинающих:

var str = 'test: '';

str = str.replace(/'/g, "'");

По существу; Я хочу решение для документа с одной страницей. Возьмите все экземпляры X и сделайте XY. Только текстовые символы.

Ответ 1

Как насчет этого, заменив @ на $:

$("body").children().each(function () {
    $(this).html( $(this).html().replace(/@/g,"$") );
});

http://jsfiddle.net/maximua/jp96C/1/

Ответ 2

Мое собственное предложение заключается в следующем:

function nativeSelector() {
    var elements = document.querySelectorAll("body, body *");
    var results = [];
    var child;
    for(var i = 0; i < elements.length; i++) {
        child = elements[i].childNodes[0];
        if(elements[i].hasChildNodes() && child.nodeType == 3) {
            results.push(child);
        }
    }
    return results;
}

var textnodes = nativeSelector(),
    _nv;
for (var i = 0, len = textnodes.length; i<len; i++){
    _nv = textnodes[i].nodeValue;
    textnodes[i].nodeValue = _nv.replace(/£/g,'€');
}

JS Fiddle demo.

Функция nativeSelector() на ответе (опубликованном Anurag) на этот вопрос: эквивалент getElementsByTagName() для textNodes.

Ответ 3

ECMAScript 2015+ подход

Подводные камни при решении этой задачи

Это кажется легкой задачей, но вы должны позаботиться о нескольких вещах:

  • Простая замена всего HTML убивает все функциональные возможности DOM, такие как прослушиватели событий
  • Замена HTML также может заменить содержимое <script> или <style>, а также теги или атрибуты HTML, что не всегда желательно
  • Изменение HTML может привести к атаке
  • Вы также можете заменить такие атрибуты, как title и alt (контролируемым образом)

Защита от атак обычно не может быть решена с использованием следующих подходов. Например, если вызов fetch считывает URL-адрес откуда-то на странице, а затем отправляет запрос на этот URL-адрес, функции, описанные ниже, не остановят это, поскольку этот сценарий по своей сути небезопасен.

Замена текстового содержимого всех элементов

Это в основном выбирает все элементы, которые содержат нормальный текст, проходит через их дочерние узлы - среди них также текстовые узлы -, ищет эти текстовые узлы и заменяет их содержимое.

При желании вы можете указать другую корневую target, например replaceOnDocument(/€ /g, "$", { target: someElement }); ; по умолчанию выбрано <body>.

const replaceOnDocument = (pattern, string, {target = document.body} = {}) => {
  // Handle 'string' — see the last section
  [
    target,
    ...target.querySelectorAll("*:not(script):not(noscript):not(style)")
  ].forEach(({childNodes: [...nodes]}) => nodes
    .filter(({nodeType}) => nodeType === document.TEXT_NODE)
    .forEach((textNode) => textNode.textContent = textNode.textContent.replace(pattern, string)));
};

replaceOnDocument(/€/g, "$");

Замена текстовых узлов, атрибутов и свойств элемента

Теперь это немного сложнее: вам нужно проверить три случая: является ли узел текстовым узлом, следует ли заменить его элемент и его атрибут или же следует заменить его элемент и его свойство. Объект- replacer предоставляет методы для текстовых узлов и для элементов.

Перед заменой атрибутов и свойств заменитель должен проверить, имеет ли элемент соответствующий атрибут; в противном случае новые атрибуты создаются нежелательно. Также необходимо проверить, является ли целевое свойство строкой, поскольку можно заменить только строки, или же свойство соответствия целевому атрибуту не является функцией, поскольку это может привести к атаке .

В приведенном ниже пример, вы можете увидеть, как использовать расширенные функции: в дополнительном третьем аргументе, вы можете добавить attrs свойство и props свойство, которое итератор (например, массив), каждый, для атрибутов, которые будут заменены и свойства для замены соответственно.

Вы также заметите, что этот фрагмент использует flatMap. Если это еще не поддерживается, используйте polyfill или заменить его reduce - concat или map - reduce - concat конструкцию, как показано в связанной документации.

const replaceOnDocument = (() => {
    const replacer = {
      [document.TEXT_NODE](node, pattern, string){
        node.textContent = node.textContent.replace(pattern, string);
      },
      [document.ELEMENT_NODE](node, pattern, string, {attrs, props} = {}){
        attrs.forEach((attr) => {
          if(typeof node[attr] !== "function" && node.hasAttribute(attr)){
            node.setAttribute(attr, node.getAttribute(attr).replace(pattern, string));
          }
        });
        props.forEach((prop) => {
          if(typeof node[prop] === "string" && node.hasAttribute(prop)){
            node[prop] = node[prop].replace(pattern, string);
          }
        });
      }
    };

    return (pattern, string, {target = document.body, attrs: [...attrs] = [], props: [...props] = []} = {}) => {
      // Handle 'string' — see the last section
      [
        target,
        ...[
          target,
          ...target.querySelectorAll("*:not(script):not(noscript):not(style)")
        ].flatMap(({childNodes: [...nodes]}) => nodes)
      ].filter(({nodeType}) => replacer.hasOwnProperty(nodeType))
        .forEach((node) => replacer[node.nodeType](node, pattern, string, {
          attrs,
          props
        }));
    };
})();

replaceOnDocument(/€/g, "$", {
  attrs: [
    "title",
    "alt",
    "onerror" // This will be ignored
  ],
  props: [
    "value" // Changing an '<input> 'value' attribute wont change its current value, so the property needs to be accessed here
  ]
});

Замена сущностями HTML

Если вам нужно, чтобы он работал с такими объектами HTML, как &shy; вышеуказанные подходы буквально приведут к появлению строки &shy; , поскольку это HTML-сущность, которая будет работать только при назначении .innerHTML или при использовании связанных методов.

Итак, давайте решим это, передав входную строку чему-то, что принимает строку HTML: новый, временный HTMLDocument. Это создается методом DOMParser parseFromString; в конце мы читаем его documentElement textContent:

string = new DOMParser().parseFromString(string, "text/html").documentElement.textContent;

Если вы хотите использовать это, выберите один из подходов выше, в зависимости от того, хотите ли вы заменить атрибуты HTML и свойства DOM в дополнение к тексту; затем просто замените комментарий //Handle 'string' — see the last section вышеупомянутой строкой.

Теперь вы можете использовать replaceOnDocument(/Güterzug/g, "G&uuml;ter&shy;zug"); ,

NB. Если вы не используете код обработки строк, вы также можете удалить { } вокруг тела функции стрелки.

Обратите внимание, что это анализирует сущности HTML, но по-прежнему не позволяет вставлять фактические теги HTML, поскольку они читали только textContent. Это также безопасно в большинстве случаев : поскольку использовался parseFromString и document страниц не затрагивался, не загружается <script> и не onerror обработчик onerror.

Вам также следует рассмотреть возможность использования \xAD вместо &shy; непосредственно в вашей строке JavaScript, если это окажется проще.

Ответ 4

В JavaScript без использования JQuery:

document.body.innerText = document.body.innerText.replace('actualword', 'replacementword');

Ответ 5

Для каждого элемента внутри документа body измените свой текст, используя . text (fn).. p >

$("body *").text(function() {
    return $(this).text().replace("x", "xy");
});

Ответ 6

Лучше всего было бы сделать эту серверную сторону или обернуть символы валюты в элементе, который вы можете выбрать, прежде чем возвращать его в браузер, однако если ни один из них не является вариантом, вы можете выбрать все текстовые узлы в теле и сделать замените на них. Ниже я делаю это, используя плагин, который написал 2 года назад, который предназначался для выделения текста. То, что я делаю, - это найти все вхождения & и обернуть его в промежутке с символом валюты класса, затем я заменю текст этих интервалов.

Демо

(function($){

    $.fn.highlightText = function () {
        // handler first parameter
        // is the first parameter a regexp?
        var re,
            hClass,
            reStr,
            argType = $.type(arguments[0]),
            defaultTagName = $.fn.highlightText.defaultTagName;

        if ( argType === "regexp" ) {
            // first argument is a regular expression
            re = arguments[0];
        }       
        // is the first parameter an array?
        else if ( argType === "array" ) {
            // first argument is an array, generate
            // regular expression string for later use
            reStr = arguments[0].join("|");
        }       
        // is the first parameter a string?
        else if ( argType === "string" ) {
            // store string in regular expression string
            // for later use
            reStr = arguments[0];
        }       
        // else, return out and do nothing because this
        // argument is required.
        else {
            return;
        }

        // the second parameter is optional, however,
        // it must be a string or boolean value. If it is 
        // a string, it will be used as the highlight class.
        // If it is a boolean value and equal to true, it 
        // will be used as the third parameter and the highlight
        // class will default to "highlight". If it is undefined,
        // the highlight class will default to "highlight" and 
        // the third parameter will default to false, allowing
        // the plugin to match partial matches.
        // ** The exception is if the first parameter is a regular
        // expression, the third parameter will be ignored.
        argType = $.type(arguments[1]);
        if ( argType === "string" ) {
            hClass = arguments[1];
        }
        else if ( argType === "boolean" ) {
            hClass = "highlight";
            if ( reStr ) {
                reStr = "\\b" + reStr + "\\b";
            }
        }
        else {
            hClass = "highlight";
        }

        if ( arguments[2] && reStr ) {
            reStr = reStr = "\\b" + reStr + "\\b";
        } 

        // if re is not defined ( which means either an array or
        // string was passed as the first parameter ) create the
        // regular expression.
        if (!re) {
            re = new RegExp( "(" + reStr + ")", "ig" );
        }

        // iterate through each matched element
        return this.each( function() {
            // select all contents of this element
            $( this ).find( "*" ).andSelf().contents()

            // filter to only text nodes that aren't already highlighted
            .filter( function () {
                return this.nodeType === 3 && $( this ).closest( "." + hClass ).length === 0;
            })

            // loop through each text node
            .each( function () {
                var output;
                output = this.nodeValue
                    .replace( re, "<" + defaultTagName + " class='" + hClass + "'>$1</" + defaultTagName +">" );
                if ( output !== this.nodeValue ) {
                    $( this ).wrap( "<p></p>" ).parent()
                        .html( output ).contents().unwrap();
                }
            });
        });
    };

    $.fn.highlightText.defaultTagName = "span";

})( jQuery );

$("body").highlightText("€","currency-symbol");
$("span.currency-symbol").text("$");

Ответ 7

Использовать метод split и join

$("#idBut").click(function() {
    $("body").children().each(function() {
        $(this).html($(this).html().split('@').join("$"));
    });
});

здесь решение

Ответ 8

Подобно ответу @max-malik, но без использования jQuery, вы также можете сделать это с помощью document.createTreeWalker:

button.addEventListener('click', e => {
  const treeWalker = document.createTreeWalker(document.body);
  while (treeWalker.nextNode()) {
    const node = treeWalker.currentNode;
    node.textContent = node.textContent.replace(/@/g, '$');
  }
})
<div>This is an @ that we are @ replacing.</div>
<div>This is another @ that we are replacing.</div>
<div>
  <span>This is an @ in a span in @ div.</span>
</div>
<br>
<input id="button" type="button" value="Replace @ with $" />

Ответ 9

Вы можете использовать:

str.replace(/text/g, "replaced text");

Ответ 10

str.replace(/replacetext/g,'actualtext')

Это заменяет все экземпляры replacetext на actualtext

Ответ 11

Как вы все равно будете использовать jQuery, попробуйте:

https://github.com/cowboy/jquery-replacetext

Тогда просто сделайте

$("p").replaceText("£", "$")

Кажется, что это хорошая работа только по замене текста и не возиться с другими элементами.

Ответ 12

Я думаю, что вы, возможно, думаете об этом.

Мой подход прост.

Добавьте вашу страницу с тегом div:

<div id="mydiv">
<!-- you page here -->
</div>

В вашем JavaScript:

var html=document.getElementById('mydiv').innerHTML;
html = html.replace(/this/g,"that");
document.getElementById('mydiv').innerHTML=html;