web-dev-qa-db-fra.com

Supprimer le texte entre les délimiteurs dans une chaîne (à l'aide d'une expression régulière?)

Considérez la nécessité de trouver une paire de jeux de caractères correspondant et de supprimer tous les caractères entre eux ainsi que ces caractères/délimiteurs.

Voici les ensembles de délimiteurs:

 []    square brackets
 ()    parentheses
 ""    double quotes
 ''    single quotes

Voici quelques exemples de chaînes qui doivent correspondre:

 Given:                       Results In:
-------------------------------------------
 Hello "some" World           Hello World
 Give [Me Some] Purple        Give Purple
 Have Fifteen (Lunch Today)   Have Fifteen
 Have 'a good'day             Have day

Et quelques exemples de chaînes qui ne devraient pas correspondre:

 Does Not Match:
------------------
 Hello "world
 Brown]co[w
 Cheese'factory

Si la chaîne donnée ne contient pas de jeu de délimiteurs correspondant, elle n'est pas modifiée. La chaîne d'entrée peut avoir plusieurs paires de délimiteurs correspondantes. Si un ensemble de 2 délimiteurs se chevauchent (c'est-à-dire he[llo "worl]d"), ce serait un cas Edge que nous pouvons ignorer ici.

L'algorithme ressemblerait à ceci:

string myInput = "Give [Me Some] Purple (And More) Elephants";
string pattern; //some pattern
string output = Regex.Replace(myInput, pattern, string.Empty);

Question: Comment pourriez-vous y parvenir avec C #? Je me penche vers une expression régulière.

Bonus: Existe-t-il des moyens faciles de faire correspondre ces délimiteurs de début et de fin dans des constantes ou dans une liste quelconque? La solution que je recherche serait facile de changer les délimiteurs au cas où les analystes commerciaux proposeraient de nouveaux ensembles de délimiteurs.

44
p.campbell

Une expression rationnelle simple serait:

string input = "Give [Me Some] Purple (And More) Elephants";
string regex = "(\\[.*\\])|(\".*\")|('.*')|(\\(.*\\))";
string output = Regex.Replace(input, regex, "");

Quant à le faire d'une manière personnalisée où vous voulez construire le regex, vous aurez juste besoin de construire les pièces:

('.*')  // example of the single quote check

Ensuite, chaque partie regex individuelle est concaténée avec un OR (le | in regex) comme dans mon exemple d'origine. Une fois que vous avez construit votre chaîne regex, exécutez-la une seule fois. La clé est d'obtenir la regex en une seule vérification, car effectuer plusieurs correspondances d'expressions régulières sur un élément, puis effectuer une itération sur de nombreux éléments entraînera probablement une baisse significative des performances.

Dans mon premier exemple, cela remplacerait la ligne suivante:

string input = "Give [Me Some] Purple (And More) Elephants";
string regex = "Your built up regex here";
string sOutput = Regex.Replace(input, regex, "");

Je suis sûr que quelqu'un publiera une expression linq cool pour construire l'expression régulière basée sur un tableau d'objets délimiteurs à faire correspondre ou quelque chose.

43
Kelsey

Un moyen simple serait de le faire:

string RemoveBetween(string s, char begin, char end)
{
    Regex regex = new Regex(string.Format("\\{0}.*?\\{1}", begin, end));
    return regex.Replace(s, string.Empty);
}

string s = "Give [Me Some] Purple (And More) \\Elephants/ and .hats^";
s = RemoveBetween(s, '(', ')');
s = RemoveBetween(s, '[', ']');
s = RemoveBetween(s, '\\', '/');
s = RemoveBetween(s, '.', '^');

La modification de l'instruction de retour comme suit évitera les espaces vides en double:

return new Regex(" +").Replace(regex.Replace(s, string.Empty), " ");

Le résultat final serait:

"Give Purple and "

Disclamer: Une seule expression régulière serait probablement plus rapide que cela.

35
Bryan Menard

Je dois ajouter le vieil adage: "Vous avez un problème et vous souhaitez utiliser des expressions régulières. Vous avez maintenant deux problèmes."

J'ai trouvé une expression rationnelle rapide qui, je l'espère, vous aidera dans la direction que vous cherchez:

[.]*(\(|\[|\"|').*(\]|\)|\"|')[.]*

Les parenthèses, crochets, guillemets doubles sont échappés tandis que le guillemet simple peut être laissé seul.

Pour mettre l'expression ci-dessus en anglais, j'autorise n'importe quel nombre de caractères avant et n'importe quel nombre après, correspondant à l'expression entre les délimiteurs correspondants.

La phrase de délimitation ouverte est (\(|\[|\"|') Ceci a une phrase de fermeture correspondante. Pour rendre cela un peu plus extensible à l'avenir, vous pouvez supprimer les délimiteurs réels et les contenir dans un fichier de configuration, une base de données ou partout où vous le souhaitez.

9
Alexis Abril

En s'appuyant sur expression régulière de Bryan Menard , j'ai créé une méthode d'extension qui fonctionnera également pour les remplacements imbriqués comme "[Test 1 [[Test2] Test3]] Hello World":

    /// <summary>
    /// Method used to remove the characters betweeen certain letters in a string. 
    /// </summary>
    /// <param name="rawString"></param>
    /// <param name="enter"></param>
    /// <param name="exit"></param>
    /// <returns></returns>
    public static string RemoveFragmentsBetween(this string rawString, char enter, char exit) 
    {
        if (rawString.Contains(enter) && rawString.Contains(exit))
        {
            int substringStartIndex = rawString.IndexOf(enter) + 1;
            int substringLength = rawString.LastIndexOf(exit) - substringStartIndex;

            if (substringLength > 0 && substringStartIndex > 0)
            {
                string substring = rawString.Substring(substringStartIndex, substringLength).RemoveFragmentsBetween(enter, exit);
                if (substring.Length != substringLength) // This would mean that letters have been removed
                {
                    rawString = rawString.Remove(substringStartIndex, substringLength).Insert(substringStartIndex, substring).Trim();
                }
            }

            //Source: https://stackoverflow.com/a/1359521/3407324
            Regex regex = new Regex(String.Format("\\{0}.*?\\{1}", enter, exit));
            return new Regex(" +").Replace(regex.Replace(rawString, string.Empty), " ").Trim(); // Removing duplicate and tailing/leading spaces
        }
        else
        {
            return rawString;
        }
    }

Dans le cas suggéré, l'utilisation de cette méthode ressemblerait à ceci:

string testString = "[Test 1 [[Test2] Test3]] Hello World";
testString.RemoveFragmentsBetween('[',']');

Retour de la chaîne "Hello World".

3
Håkon Seljåsen

Utilisez le Regex suivant

(\{\S*\})

Ce regex fait qu'il remplace toutes les occurrences de {Word} par le mot modifié avec lequel vous voulez le remplacer.

Quelques exemples de code c #:

 static readonly Regex re = new Regex(@"(\{\S*\})", RegexOptions.Compiled);
        /// <summary>
        /// Pass text and collection of key/value pairs. The text placeholders will be substituted with the collection values.
        /// </summary>
        /// <param name="text">Text that containes placeholders such as {fullname}</param>
        /// <param name="fields">a collection of key values pairs. Pass <code>fullname</code> and the value <code>Sarah</code>. 
        /// DO NOT PASS keys with curly brackets <code>{}</code> in the collection.</param>
        /// <returns>Substituted Text</returns>
        public static string ReplaceMatch(this string text, StringDictionary fields)
        {
            return re.Replace(text, match => fields[match.Groups[1].Value]);
        }

Dans une phrase comme

Regex Hero est un testeur d'expression en ligne en temps réel {en ligne {Silverlight} régulier}.

Il ne remplacera que {Silverlight} et ne commencera pas du premier {crochet au dernier} crochet.

0
jaxxbo