Для тех, кто хочет быстро работающий код, я отправляю код я использую на основе принятого ответа:
public static string GetFirstWordsRegEx(string s, int wordCount, string truncateSuffix = " [...]")
{
// replace with string.Format for C# less than 6.0
string pattern = [email protected]"^\W*\w+(?:\W+\w+){{{wordCount - 1}}}";
var regex = new Regex(pattern);
var match = regex.Match(s);
if (!match.Success)
return s;
var ret = match.Value;
return ret.Length < s.Length ? ret + truncateSuffix : ret;
}
Он получает первые wordCount
слова вместе с их разделители или весь текст, если он имеет менее wordCount
. Кроме того, позволяет добавлять суффикс при усечении.
[EDIT]
Wiktor Stribiżew
«s сомнения, о которых решение более высокую производительность, сделали тест его. Я буду называть первое решение «классическим», второе «регулярное выражение» и третье «скомпилированное Regex».
Первый в вопросе, второй в начале этого ответа и третий один ниже:
// generated all possible text truncation patterns
private static readonly List<Regex> FirstWordRegexes = new List<Regex>
{
new Regex(@"^\W*\w+(?:\W+\w+){0}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){1}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){2}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){3}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){4}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){5}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){6}", RegexOptions.Compiled),
// ...
// removed for brevity
// ...
new Regex(@"^\W*\w+(?:\W+\w+){147}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){148}", RegexOptions.Compiled),
new Regex(@"^\W*\w+(?:\W+\w+){149}", RegexOptions.Compiled),
};
public static string GetFirstWordsRegExOptimized(string s, int wordCount, string truncateSuffix = " [...]")
{
var regex = FirstWordRegexes[wordCount-1];
var match = regex.Match(s);
if (!match.Success)
return s;
var ret = match.Value;
return ret.Length < s.Length ? ret + truncateSuffix : ret;
}
код Test
var sw = new Stopwatch();
var rand = new Random();
const int minValue = 20;
const int maxValue = 150;
#region warm up
sw.Start();
Console.WriteLine($"Warming up...");
// _testStrings contains 100K random real texts which may be longer or not than first words truncation value
foreach (var str in _testStrings)
{
var dummy = str;
}
Console.WriteLine($"Warm up took {sw.ElapsedMilliseconds} ms");
#endregion
#region Classic C# approach
foreach (var str in _testStrings)
{
int wordCount = rand.Next(minValue, maxValue);
var firstWords = Utils.GetFirstWords(str, wordCount);
}
Console.WriteLine($"Classic code took {sw.ElapsedMilliseconds} ms");
sw.Restart();
#endregion
#region Uncompiled regex
sw.Start();
foreach (var str in _testStrings)
{
int wordCount = rand.Next(minValue, maxValue);
var firstWords = Utils.GetFirstWordsRegEx(str, wordCount);
}
Console.WriteLine($"Uncompiled regex code took {sw.ElapsedMilliseconds} ms");
sw.Restart();
#endregion
#region Compiled regex
sw.Start();
foreach (var str in _testStrings)
{
int wordCount = rand.Next(minValue, maxValue);
var firstWords = Utils.GetFirstWordsRegExOptimized(str, wordCount);
}
Console.WriteLine($"Compiled regex code took {sw.ElapsedMilliseconds} ms");
sw.Restart();
#endregion
Результаты
Классический код занял 953 мс
Неоткомпилированный код регулярного выражения взял 5559 мса
Составителя код регулярного выражения взял 4194 мс
Как и ожидались, составленное регулярное выражение было быстрее, чем неоткомпилированные один. Однако классическая версия была намного быстрее.
Я думаю, вы могли бы попробовать 'Regex.Replace (s, @" (? S)^(\ W * \ w + (?: \ W + \ w +) {4}). * "," $ 1 [... ] ")', см. [this regex demo] (http://regexstorm.net/tester?p=%28%3fs%29%5e%28%5cW*%5cw%2b%28%3f%3a%5cW% 2б% 5cw% 2b% 29% 7b4% 7d% 29. * & я = + quick_brown% 2c + fox1 + прыжки + над + кнопки + ленивым + собака + & г =% 241 +% 5б ...% 5d). Если ожидается, что строка содержит менее 5 слов, и результат должен содержать весь ввод, замените '{4}' на '{0,4}'. –
Да, он корректно работает с Match (нет необходимости заменять). Пожалуйста, разместите его как ответ, чтобы я мог его принять. Спасибо. – Alexei
Regex будет медленнее, чем ваш метод (по крайней мере, если строка большая, так что это важно), поэтому не заменяйте ее по соображениям производительности. –