Удалить текст между разделителями в строке (с использованием регулярного выражения?)
Рассмотрим требование найти совпадающую пару наборов символов и удалить любые символы между ними, а также те символы/разделители.
Вот наборы разделителей:
[] 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);
Вопрос: Как бы вы это сделали с С#? Я склоняюсь к регулярному выражению.
Бонус: Есть ли простые способы сопоставления этих разделителей начала и конца в константах или в некотором списке? Решение, которое я ищу, было бы легко изменить разделители, если бизнес-аналитики придумают новые наборы разделителей.
Ответы
Ответ 1
Простым регулярным выражением будет:
string input = "Give [Me Some] Purple (And More) Elephants";
string regex = "(\\[.*\\])|(\".*\")|('.*')|(\\(.*\\))";
string output = Regex.Replace(input, regex, "");
Для того, чтобы сделать это обычным способом, когда вы хотите создать регулярное выражение, вам просто нужно создать части:
('.*') // example of the single quote check
Затем каждая часть регулярного выражения объединяется с OR (в regex), как в моем первоначальном примере. Как только вы построите строку регулярных выражений, просто запустите ее один раз. Ключ состоит в том, чтобы получить регулярное выражение в одну проверку, потому что выполнение множества регулярных выражений на одном элементе, а затем повторение множества элементов, вероятно, приведет к значительному снижению производительности.
В моем первом примере, который заменил бы следующую строку:
string input = "Give [Me Some] Purple (And More) Elephants";
string regex = "Your built up regex here";
string sOutput = Regex.Replace(input, regex, "");
Я уверен, что кто-то опубликует классное выражение linq для создания регулярного выражения на основе массива объектов-разделителей для соответствия или чего-то еще.
Ответ 2
Простым способом было бы это сделать:
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 на следующее позволит избежать дублирования пустых пространств:
return new Regex(" +").Replace(regex.Replace(s, string.Empty), " ");
Конечным результатом для этого будет:
"Give Purple and "
Disclamer: одно регулярное выражение, вероятно, будет быстрее, чем это.
Ответ 3
Мне нужно добавить старую пословицу: "У вас есть проблема, и вы хотите использовать регулярные выражения. Теперь у вас есть две проблемы".
Я придумал быстрое регулярное выражение, которое, надеюсь, поможет вам в том направлении, в котором вы смотрите:
[.]*(\(|\[|\"|').*(\]|\)|\"|')[.]*
Скобки, скобки, двойные кавычки экранируются, а одиночная кавычка может быть оставлена одна.
Чтобы поставить вышеуказанное выражение на английский язык, я разрешаю любое количество символов до и после любого числа после соответствия между выражениями между соответствующими разделителями.
Открытая фраза-разделитель (\(|\[|\"|')
У этого есть соответствующая заключительная фраза. Чтобы сделать это еще более расширяемым в будущем, вы можете удалить фактические разделители и содержать их в файле конфигурации, базе данных или там, где вы можете выбрать.
Ответ 4
Основываясь на регулярном выражении Брайана Менарга я сделал метод расширения, который также будет работать для вложенных заметок, таких как "[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: /questions/131476/remove-text-in-between-delimiters-in-a-string-using-a-regex/790342#790342
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".
Ответ 5
Используйте следующее Regex
(\{\S*\})
Что делает это регулярное выражение, он заменяет любые вхождения {word} с измененнымWord, который вы хотите заменить.
Пример кода С#:
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 является оператором {онлайн {Silverlight} Regular} в реальном времени Tester.
Он заменит только {Silverlight} и не будет начинаться с первой скобки {bracket to the last}.