75 votes

Alternative à l'expression régulière: correspond à toutes les instances qui ne se trouvent pas entre guillemets

À partir de cette q/r, j'en ai déduit que toutes les instances d'une regex pas à l'intérieur des guillemets, c'est impossible. Qui est, il peut ne pas correspondre échappé guillemets (ex: "this whole \"match\" should be taken"). Si il y a un moyen de le faire que je ne connais pas, qui permettrait de résoudre mon problème.

Si pas, cependant, je voudrais savoir si il existe une alternative efficace qui pourrait être utilisé en JavaScript. J'ai réfléchi un peu, mais ne pouvez pas venir avec quelque des solutions élégantes qui serait à l'œuvre dans la plupart, si pas tous les cas.

Plus précisément, j'ai juste besoin de l'alternative de travailler avec .split() et .replace() les méthodes, mais si elle pouvait être plus généralisée, qui serait le meilleur.

Par Exemple:
Une entrée de chaîne de:
+bar+baz"not+or\"+or+\"this+"foo+bar+
remplacement de + avec #, pas à l'intérieur des guillemets, serait de retour:
#bar#baz"not+or\"+or+\"this+"foo#bar#

124voto

Jens Points 14829

En fait, vous pouvez faire correspondre toutes les instances d'une regex pas à l'intérieur des guillemets pour toute chaîne de caractères, où chaque guillemet ouvrant est fermé à nouveau. Dire, comme vous l'exemple ci-dessus, vous voulez faire correspondre \+.

L'observation essentielle est ici, qu'un mot est en dehors des guillemets s'il y a un même nombre de citations par la suite. Cela peut être modélisé comme un "look-ahead" affirmation:

\+(?=([^"]*"[^"]*")*[^"]*$)

Maintenant, vous voulez pas compter échappé citations. Cela devient un peu plus compliqué. Au lieu de [^"]* , qui a avancé à la prochaine citation, vous devez tenir compte de barres obliques inverses et ainsi utiliser [^"\\]*. Après vous arrivez à une barre oblique inverse ou un devis, vous avez besoin d'ignorer le caractère suivant si vous rencontrez une barre oblique inverse, ou bien passer à la suivante sans échappement devis. Qui ressemble (\\.|"([^"\\]*\\.)*[^"\\]*"). Combiné, vous arrivez à

\+(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$)

J'avoue c'est un peu cryptique. =)

77voto

zx81 Points 22309

Azmisov, ressusciter cette question parce que vous avez dit que vous cherchiez any efficient alternative that could be used in JavaScript et any elegant solutions that would work in most, if not all, cases. (Trouvé votre question tout en faisant un peu de recherche pour une regex bounty quête.)

Il arrive à être une simple solution générale qui n'était pas mentionné.

En comparaison avec les alternatives, la regex pour cette solution est d'une simplicité déconcertante:

"[^"]+"|(\+)

L'idée est que nous avons du match, mais ignorer quoi que ce soit dans les citations à neutraliser que le contenu (sur le côté gauche de l'alternance). Sur le côté droit, nous capter toute l' + qui n'ont pas été neutralisé dans le Groupe 1, et la fonction remplacer examine Groupe 1. Ici est plein de code opérationnel:

<script>
var subject = '+bar+baz"not+or\"+or+\"this+"foo+bar+';
var regex = /"[^"]+"|(\+)/g;
replaced = subject.replace(regex, function(m, group1) {
    if (group1 == "" ) return m;
    else return "#";
});
document.write(replaced);
</script>

Démo en ligne

Vous pouvez utiliser le même principe pour le match ou split. Voir la question et l'article en référence, qui sera aussi le point de vous des exemples de code.

Espérons que cela vous donne une idée différente de façon très générale pour ce faire. :)

Référence

  1. Comment faire correspondre motif, sauf dans des situations s1, s2, s3
  2. Comment faire pour correspondre à un modèle, à moins que...

6voto

Mike Samuel Points 54712

Vous pouvez le faire en trois étapes.

  1. Utiliser une regex remplacement global pour extraire toutes les chaînes de caractères du corps contenu dans une table d'appoint.
  2. Faites votre virgule traduction
  3. Utiliser une regex remplacement global de swap de la chaîne organes de retour

Le Code ci-dessous

// Step 1
var sideTable = [];
myString = myString.replace(
    /"(?:[^"\\]|\\.)*"/g,
    function (_) {
      var index = sideTable.length;
      sideTable[index] = _;
      return '"' + index + '"';
    });
// Step 2, replace commas with newlines
myString = myString.replace(/,/g, "\n");
// Step 3, swap the string bodies back
myString = myString.replace(/"(\d+)"/g,
    function (_, index) {
      return sideTable[index];
    });

Si vous exécutez après la mise

myString = '{:a "ab,cd, efg", :b "ab,def, egf,", :c "Conjecture"}';

vous devriez obtenir

{:a "ab,cd, efg"
 :b "ab,def, egf,"
 :c "Conjecture"}

Il fonctionne, parce que après l'étape 1,

myString = '{:a "0", :b "1", :c "2"}'
sideTable = ["ab,cd, efg", "ab,def, egf,", "Conjecture"];

donc, la seule des virgules dans myString sont des chaînes de caractères en dehors. L'étape 2, puis se tourne

myString = '{:a "0"\n :b "1"\n :c "2"}'

et enfin nous remplacer les cordes qui ne contiennent que des nombres avec leur contenu original.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X