Удалить текстовые промежуточные разделители в строке (используя регулярное выражение?) - PullRequest
43 голосов
/ 01 сентября 2009

Рассмотрим требование найти подходящую пару наборов символов и удалить любые символы между ними, и эти символы / разделители.

Вот наборы разделителей:

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

Вот несколько примеров строк, которые должны соответствовать:

 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

И несколько примеров строк, которые не должны совпадать:

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

Если данная строка не содержит совпадающего набора разделителей, она не изменяется. Во входной строке может быть много совпадающих пар разделителей. Если набор из 2 разделителей перекрывается (то есть he[llo "worl]d"), это будет крайний случай, который мы можем игнорировать здесь.

Алгоритм будет выглядеть примерно так:

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

Вопрос: Как бы вы достигли этого с C #? Я склоняюсь к регулярному выражению.

Бонус: Существуют ли простые способы сопоставления начального и конечного разделителей в константах или в каком-либо списке? Решение, которое я ищу, будет легко изменить разделители, если бизнес-аналитики придумают новые наборы разделителей.

Ответы [ 5 ]

42 голосов
/ 01 сентября 2009

Простое регулярное выражение будет:

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

Что касается пользовательского способа построения регулярного выражения, вам просто нужно создать части:

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

Затем каждую отдельную часть регулярного выражения объединяем с помощью ИЛИ (| в регулярном выражении), как в моем исходном примере. Как только вы построите строку регулярных выражений, просто запустите ее один раз. Ключевым моментом является включение регулярного выражения в одну проверку, поскольку выполнение множества сопоставлений регулярных выражений для одного элемента с последующим повторением множества элементов, вероятно, приведет к значительному снижению производительности.

В моем первом примере это займет место следующей строки:

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

Я уверен, что кто-то опубликует классное выражение linq для построения регулярного выражения на основе массива сопоставляемых объектов или чего-то подобного.

34 голосов
/ 01 сентября 2009

Простой способ сделать это:

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, '.', '^');

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

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

Окончательный результат для этого будет:

"Give Purple and "

Disclamer : Одно регулярное выражение, вероятно, будет быстрее этого

9 голосов
/ 01 сентября 2009

Я должен добавить старую поговорку: «У вас есть проблема, и вы хотите использовать регулярные выражения. Теперь у вас есть две проблемы».

Я придумал быстрое регулярное выражение, которое, надеюсь, поможет вам в том направлении, куда вы смотрите:

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

Скобки, скобки, двойные кавычки экранированы, а одиночную кавычку можно оставить в покое.

Чтобы перевести вышеприведенное выражение на английский, я допускаю любое количество символов до и любое число после совпадения выражения между соответствующими разделителями.

Открытая фраза-разделитель (\(|\[|\"|') Это имеет соответствующую заключительную фразу. Чтобы сделать это немного более расширяемым в будущем, вы можете удалить фактические разделители и содержать их в файле конфигурации, базе данных или где угодно по вашему выбору.

3 голосов
/ 23 августа 2016

Основываясь на Регулярном выражении Брайана Менарда , я создал метод расширения, который также будет работать для вложенных замен, таких как «[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;
        }
    }

Использование этого метода в предложенном случае будет выглядеть следующим образом:

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

Возвращение строки "Hello World".

0 голосов
/ 17 апреля 2015

Используйте следующее регулярное выражение

(\{\S*\})

То, что делает это регулярное выражение, это то, что он заменяет все вхождения {word} измененным словом, которым вы хотите его заменить.

Пример кода 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]);
        }

В предложении, таком как

Regex Hero представляет собой {online { Silverlight } регулярное} выражение в реальном времени Тестер.

Он заменит только { Silverlight } и не начинается с первой {скобки до последней} скобки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...