web-dev-qa-db-fra.com

Rechercher et remplacer des caractères spécifiques dans un document avec JS

Je me demande s'il est possible d'utiliser JavaScript ou jQuery de manière légère pour détecter un caractère de texte spécifique dans un document; diteset trouvez toutes les occurrences de ce caractère. Et alors! Ecrit une capacité à remplacer toutes les instances de celle-ci avec, par exemple, un $ .

J'ai trouvé cet extrait pour commencer:

var str = 'test: '';

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

Essentiellement; Je cherche une solution pour un document d'une page. Prenez toutes les instances de X et faites-le XY. Seuls les caractères du texte. 

20
No-Spex

Que diriez-vous de ceci, en remplaçant @ par $:

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

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

23
Max Malyk

Ma propre suggestion est la suivante:

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,'€');
}

Démo de JS Fiddle .

La fonction nativeSelector() provient de une réponse (publiée par Anurag ) à cette question: getElementsByTagName () équivalente pour textNodes .

19
David Thomas

Approche ECMAScript 2015+

Pièges lors de la résolution de cette tâche

Cela semble être une tâche facile, mais vous devez prendre en charge plusieurs choses:

  • Remplacer simplement le code HTML entier tue toutes les fonctionnalités du DOM, comme les écouteurs d'événements
  • Le remplacement du code HTML peut également remplacer le contenu <script> ou <style>, ou les balises ou attributs HTML, ce qui n'est pas toujours souhaitable
  • Changer le code HTML peut entraîner une attaque xss
  • Vous voudrez peut-être également remplacer des attributs tels que title et alt (de manière contrôlée)

La protection contre les attaques xss ne peut généralement pas être résolue en utilisant les approches ci-dessous. Par exemple. Si un appel fetch lit une URL quelque part sur la page, puis envoie une demande à cette URL, les fonctions ci-dessous n'arrêteront pas cela, car ce scénario est intrinsèquement dangereux.

Remplacement du contenu textuel de tous les éléments

Cela sélectionne essentiellement tous les éléments contenant du texte normal, passe par leurs nœuds enfants (parmi ceux-ci également des nœuds de texte), recherche ces nœuds de texte et remplace leur contenu.

Vous pouvez éventuellement spécifier une racine différente target, par exemple. replaceOnDocument(/€/g, "$", { target: someElement });; Par défaut, le <body> est choisi.

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, "$");

Remplacement des nœuds de texte, des attributs d'éléments et des propriétés

Maintenant, ceci est un peu plus complexe: vous devez vérifier trois cas: si un nœud est un nœud text, s’il s’agit d’un élément et que son attribut doit être remplacé, ou s’il s’agit d’un élément et de son property doit être remplacé. Un objet replacer fournit des méthodes pour les nœuds de texte et pour les éléments.

Avant de remplacer des attributs et des propriétés, le remplaçant doit vérifier si l'élément a un attribut correspondant. sinon, de nouveaux attributs sont créés, de manière non souhaitable. Il doit également vérifier si la propriété ciblée est une chaîne, car seules les chaînes peuvent être remplacées, ou si la propriété correspondante à l'attribut ciblé n'est pas une fonction, car cela peut entraîner une attaque xss .

Dans l'exemple ci-dessous, vous pouvez voir comment utiliser les fonctionnalités étendues: dans le troisième argument facultatif, vous pouvez ajouter une propriété attrs et une propriété props, qui est un élément itératif (par exemple, un tableau), pour les attributs à remplacer et les propriétés à remplacer, respectivement.

Vous remarquerez également que cet extrait utilise flatMap . Si cela n’est pas pris en charge, utilisez un polyfill ou remplacez-le par la construction reduceconcat ou mapreduceconcat, comme indiqué dans la documentation liée.

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>`’s `value` attribute won’t change its current value, so the property needs to be accessed here
  ]
});

Remplacement par des entités HTML

Si vous avez besoin de le faire fonctionner avec des entités HTML telles que &shy;, les approches ci-dessus ne produiront littéralement que la chaîne &shy;, car il s’agit d’une entité HTML et ne fonctionnera que lors de l’affectation de .innerHTML ou de l’utilisation de méthodes connexes.

Réservons-le en passant la chaîne d’entrée à quelque chose qui accepte une chaîne HTML: une nouvelle variable temporaire HTMLDocument. Ceci est créé par la méthode DOMParser ’s parseFromString; à la fin nous lisons sa documentElement ’s textContent:

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

Si vous souhaitez utiliser cela, choisissez l'une des approches ci-dessus, selon que vous souhaitez ou non remplacer les attributs HTML et les propriétés DOM en plus du texte; remplacez simplement le commentaire // Handle `string` — see the last section par la ligne ci-dessus.

Vous pouvez maintenant utiliser replaceOnDocument(/Güterzug/g, "G&uuml;ter&shy;zug");.

NB: Si vous n’utilisez pas le code de traitement de chaîne, vous pouvez également supprimer le {} autour du corps de la flèche.

Notez que ceci analyse les entités HTML mais n'autorise toujours pas l'insertion de balises HTML réelles, car nous ne lisons que la variable textContent. Ceci est également sûr contre la plupart des cas de xss : puisque nous utilisons parseFromString et que la page document n’est pas affectée, aucun <script> n’est téléchargé et aucun gestionnaire onerror ne s’exécute.

Vous devriez également envisager d'utiliser \xAD au lieu de &shy; directement dans votre chaîne JavaScript, si cela s'avère plus simple.

10
Xufox

En javascript sans utiliser jquery

document.body.innerText.replace('actualword', 'replacementword');
1
sohail.hussain.dyn

Pour chaque élément du document body, modifiez son texte à l'aide de la fonction .text (fn).

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

Utiliser la méthode split and join

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

voici solution

1
Suresh Mahawar

Le mieux serait d’effectuer cette opération côté serveur ou d’envelopper les symboles monétaires dans un élément que vous pouvez sélectionner avant de le renvoyer au navigateur. Toutefois, si aucune option n’est proposée, vous pouvez sélectionner tous les nœuds de texte dans le corps et les remplacer . Ci-dessous, je le fais à l'aide d'un plug-in que j'ai écrit il y a 2 ans et qui était destiné à mettre en évidence du texte. Ce que je fais est de trouver toutes les occurrences de € et de l'envelopper dans une étendue avec le symbole de devise de classe, puis je remplace le texte de ces étendues.

Démo

(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("$");
1
Kevin B

Comme vous utiliserez de toute façon jQuery, essayez:

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

Alors fais juste

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

Cela semble bien faire de ne remplacer que du texte et de ne pas jouer avec d'autres éléments

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

Ceci remplace toutes les instances de replacetext par actualtext

0
Krishna

Semblable à la réponse de @ max-malik, mais sans utiliser jQuery, vous pouvez le faire avec 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 $" />

0
Jsilvermist

Vous pouvez utiliser:

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