4
votes

Rechercher une sous-chaîne contenant la forme échappée d'un délimiteur (Regexp)

Bonjour à tous!

Je joue avec le démarquage, je gère les marqueurs en ligne et les caractères échappés.

Problème:

Je veux transformer ceci: du texte * un certain nombre \ * un autre numéro * plus de texte

Dans ceci: du texte un certain nombre * un autre numéro plus de texte

Mon modèle actuel est: /((?!\\)\*)(.*?)((?!\\)\*)/g

Mais le groupe (. *?) semble capturer le caractère \ , donc le troisième groupe trouve le deuxième caractère * et s'arrête à la recherche du troisième, qui devrait être sa cible.

Solution possible:

Je peux résoudre ce problème en utilisant la recherche négative: /(?, mais j'aimerais l'éviter, si c'est possible.

Puis-je modifier mon autre modèle pour qu'il fonctionne?


6 commentaires

regex101.com/r/afdKgi/2 ?


@ splash58 Le publieriez-vous comme réponse?


/(^|[^\\ )\*(.*?)($|[^\\ )\*/g ne fonctionne pas si le * est au début de la chaîne. Même si vous corrigez cela, ne correspondra pas \\ * à un certain nombre \ * autre numéro * plus de texte qui devrait être puisque le premier \\ définit une barre oblique inverse.


@ WiktorStribiżew regex101.com/r/afdKgi/6


@ splash58 Ne fonctionne toujours pas , \\\ * un certain nombre \ * autre nombre * plus de texte commence par une barre oblique inverse et un échappé * , mais il y a une correspondance. Ce type de tâche ne peut pas être résolu avec . *? et les recherches.


@ Nekomajin42 Veuillez consulter ma réponse ci-dessous pour une solution de contournement plus simple.


3 Réponses :


1
votes

Vous pouvez utiliser cette

const regex = /\*(.*?[^\\])\*/gm;
const str = `some text *some number \\* other number* blah blah *some number \\* other number* more text`;
const subst = `<strong>$1</strong>`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);
const finalResult = result.replace(/\\(.)/g,'$1')   //replacing escaped character here

console.log(finalResult);

Ceci utilise l'expression régulière ci-dessus pour trouver * jusqu'au dernier * . Et qu'avec \\ (.) , je trouve le caractère échappé et je le remplace par le groupe capturé.

const regex = /\*(.*)\*/gm;
const str = `some text *some number \\* other number* more text`;
const subst = `<strong>$1</strong>`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);
const finalResult = result.replace(/\\(.)/,'$1')   //replacing escaped character here

console.log(finalResult);

MISE À JOUR: Pour faire correspondre plus d'une sous-chaîne

\*(.*)\*


3 commentaires

Pouvez-vous le modifier pour qu'il fonctionne avec plusieurs instances de la sous-chaîne dans str ?


@ Nekomajin42 vérifiez la mise à jour. faites-moi savoir si quelque chose manque


Le modèle mis à jour semble ne trouver que le premier et le dernier marqueur * dans la chaîne, et les mêmes marqueurs sont ignorés entre eux.



2
votes

Vous pouvez utiliser

var str = "some text *some number \\* other number* more text";
console.log(
 str.replace(/((?:^|[^\\])(?:\\{2})*)\*([^\\*]*(?:\\[\s\S][^*\\]*)*)\*/g, 
   function($0, $1, $2) { return $1 + '<strong>' + $2.replace(/\\([\s\S])/g, '$1') + '</strong>'; }
 )
)

Le premier / ((?: ^ | [^ \\]) (?: \\ {2}) *) \ * ([^ \\ *] * (?: \ \ [\ s \ S] [^ * \\] *) *) \ * / g regex correspond à toutes les chaînes de * sans échappement :

  • ((?: ^ | [^ \\]) (?: \\ {2}) *) - Groupe 1:
    • (?: ^ | [^ \\]) - début de chaîne ou non-barre oblique inverse
    • (?: \\ {2}) * - 0+ occurrences de double barre oblique inverse (cela évite de faire correspondre * échappé)
  • \ * - un * caractère
  • ([^ \\ *] * (?: \\ [\ s \ S] [^ * \\] *) *) - Groupe 2:
    • [^ \\ *] * - 0+ caractères autres que \ et *
    • (?: \\ [\ s \ S] [^ * \\] *) * - 0+ séquences de
      • \\ [\ s \ S] - un \ et n'importe quel caractère
      • [^ * \\] * - 0+ caractères autres que \ et *
  • \ * - un caractère * .

La correspondance est passée à la méthode anonyme comme deuxième argument de la méthode replace et le contenu du groupe 2 est traité pour "unescape" toute séquence d'échappement avec . replace (/ \\ ([\ s \ S]) / g, '$ 1') : \\ correspond à une barre oblique inverse et ([\ s \ S]) correspond et capture n'importe quel caractère du groupe 1, et c'est ce qui reste après le remplacement par l'espace réservé du groupe $1.


1 commentaires

Le truc, c'est que j'ai besoin de ce truc à des fins éducatives, et c'est beaucoup plus compliqué que l'idéal, mais merci pour l'explication détaillée.



0
votes

Il pourrait y avoir un moyen plus simple d'accomplir la même tâche en utilisant l'expression régulière suivante:

var str = `some text *some number \\* other number* more text`

console.log(str.replace(/\\.|\*((\\.|[^*])+)\*/g, function(match, $1) {
	return $1 ? '<strong>' + $1 + '</strong>' : match;
}));

L'idée correspond à une chaîne désirée devrait se produire après que tous les caractères échappés sont consommés. Nous essayons de faire correspondre tous les caractères échappés en utilisant le premier côté de l'alternance, puis à la deuxième tentative, nous voulons faire correspondre notre modèle souhaité s'il existe.

Code JS:

\\.|\*((\\.|[^*])+)\*

Breakdown:

  • \\. Faire correspondre un caractère échappé
  • | Ou
  • \ * Correspond à un littéral *
  • ( Début du premier groupe de capture
    • ( Début du deuxième groupe de capture
      • \\. Faire correspondre un caractère échappé
      • | Ou
      • [^ *] + Correspond à tout sauf *
    • ) + Fin du deuxième groupe de capture, répéter une ou plusieurs fois
    • ) Fin du premier groupe de capture
  • \ * Correspond à un littéral *


2 commentaires

Ce modèle semble correspondre aux sous-chaînes \ * en dehors des marqueurs * .


Cela correspond mais ne remplace pas. Il existe un rappel pour la méthode replace . Même la réponse que vous avez acceptée comporte deux appels consécutifs à replace () , ce qui complique les choses. Si vous rencontrez des problèmes, veuillez donner un exemple.