Форматирование предложений в строке с использованием c#

StackOverflow https://stackoverflow.com/questions/2135863

Вопрос

У меня есть строка с несколькими предложениями. Как использовать первое письмо первого слова в каждом предложении. Что -то вроде форматирования абзаца в Word.

Например, «Это какой -то код. Код находится в C#.« Отвировка должна быть «Это какой -то код. Код в C#».

Одним из способов будет разделение строки на основе «». а затем используйте первое письмо, а затем вернемся.

Есть ли лучшее решение?

Это было полезно?

Решение

По моему мнению, когда дело доходит до потенциально сложного сопоставления и замены строк на основе правил-вы не можете получить гораздо лучше, чем решение на основе режима (несмотря на то, что их так трудно читать!). На мой взгляд, это обеспечивает лучшую производительность и эффективность памяти - вы будете удивлены тем, насколько быстро это будет.

Я бы использовал Перегрузка regex.replace, которая принимает входную строку, шаблон режима и делегат MatchEvaluator. Анкет MatchEvaluator - это функция, которая принимает Match объект как вход и возвращает замену строки.

Вот код:

public static string Capitalise(string input)
{
  //now the first character
  return Regex.Replace(input, @"(?<=(^|[.;:])\s*)[a-z]",
    (match) => { return match.Value.ToUpper(); });
}

В регулярном выражении используется конструкция (? <=) (Положительная ширина с нулевой шириной), чтобы ограничить захваты только символами AZ, которому предшествовали начало строки, или знаки препинания, которые вы хотите. в [.;:] кусочнее, вы можете добавить дополнительные, которые вы хотите (например, [.;:?."] добавить ? и "персонажи.

Это также означает, что вашему MatchEvaluator не нужно делать никаких ненужных соединений строки (чего вы хотите избежать по причинам производительности).

Все остальные вещи, упомянутые одним из других ответов об использовании regexoptions.compiled, также актуальны с точки зрения производительности. Метод Static Regex.replace предлагает очень похожие преимущества для производительности, хотя (есть только дополнительный поиск словаря).

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

РЕДАКТИРОВАТЬ

Поместил это решение против Ахмада, так как он вполне справедливо отметил, что наглядный взгляд может быть менее эффективным, чем делать это.

Вот грубый эталон, который я сделал:

public string LowerCaseLipsum
{
  get
  {
    //went to lipsum.com and generated 10 paragraphs of lipsum
    //which I then initialised into the backing field with @"[lipsumtext]".ToLower()
    return _lowerCaseLipsum;
  }
 }
 [TestMethod]
 public void CapitaliseAhmadsWay()
 {
   List<string> results = new List<string>();
   DateTime start = DateTime.Now;
   Regex r = new Regex(@"(^|\p{P}\s+)(\w+)", RegexOptions.Compiled);
   for (int f = 0; f < 1000; f++)
   {
     results.Add(r.Replace(LowerCaseLipsum, m => m.Groups[1].Value
                      + m.Groups[2].Value.Substring(0, 1).ToUpper()
                           + m.Groups[2].Value.Substring(1)));
   }
   TimeSpan duration = DateTime.Now - start;
   Console.WriteLine("Operation took {0} seconds", duration.TotalSeconds);
 }

 [TestMethod]
 public void CapitaliseLookAroundWay()
 {
   List<string> results = new List<string>();
   DateTime start = DateTime.Now;
   Regex r = new Regex(@"(?<=(^|[.;:])\s*)[a-z]", RegexOptions.Compiled);
   for (int f = 0; f < 1000; f++)
   {
     results.Add(r.Replace(LowerCaseLipsum, m => m.Value.ToUpper()));
   }
   TimeSpan duration = DateTime.Now - start;
   Console.WriteLine("Operation took {0} seconds", duration.TotalSeconds);
 }

В сборке выпуска мое решение было примерно на 12% быстрее, чем у Ахмада (1,48 секунды, в отличие от 1,68 секунды).

Интересно, однако, что если бы это было сделано с помощью статического метода regex.replace, оба были примерно на 80% медленнее, а мое решение было медленнее, чем у Ахмада.

Другие советы

Вот решение, которое использует категорию знаков препинания, чтобы избежать необходимости указать.!? »И т. Д. Хотя вы, безусловно, должны проверить, охватывает ли она ваши потребности или явно их установить. Прочитайте в категории« P »в рамках« поддерживаемого общего Unicode General Categories. "Раздел, расположенный на Страница классов персонажей MSDN.

string input = @"this is some code. the code is in C#? it's great! In ""quotes."" after quotes.";
string pattern = @"(^|\p{P}\s+)(\w+)";

// compiled for performance (might want to benchmark it for your loop)
Regex rx = new Regex(pattern, RegexOptions.Compiled);

string result = rx.Replace(input, m => m.Groups[1].Value
                                + m.Groups[2].Value.Substring(0, 1).ToUpper()
                                + m.Groups[2].Value.Substring(1));

Если вы решите не использовать \p{P} Класс, вам нужно было бы указать персонажей самостоятельно, аналогично:

string pattern = @"(^|[.?!""]\s+)(\w+)";

РЕДАКТИРОВАТЬ: Ниже приведен обновленный пример для демонстрации 3 шаблонов. Первый показывает, как все пунктивы влияют на корпус. Второе показывает, как выбрать и выбрать определенные категории пунктуации, используя вычитание класса. Он использует все пунктивы при удалении конкретных групп пунктуации. Третий похож на 2 -й, но использует разные группы.

Ссылка MSDN не объясняет, о чем ссылаются некоторые категории пунктуации, так что вот расстройство:

  • п: Все пунктивы (содержит все категории ниже)
  • ПК: подчеркивать _
  • ПД: бросаться -
  • Пса: Открыть скобку, скобки и брекеты ( [ {
  • Финиш: Закрытие скобок, скобки и скобки ) ] }
  • Пи: Начальные однократные/двойные кавычки (MSDN говорит, что «может вести себя как PS/PE в зависимости от использования»)
  • Пф: Окончательные одно/двойные кавычки (применяется MSDN PI Note)
  • В: Другая пунктуация, такая как запятые, колоны, полуколоны и черты ,, :, ;, \, /

Тщательно сравните, как эти группы влияют на результаты. Это должно предоставить вам большую степень гибкости. Если это не кажется желательным, то вы можете использовать конкретные символы в классе символов, как показано ранее.

string input = @"foo ( parens ) bar { braces } foo [ brackets ] bar. single ' quote & "" double "" quote.
dash - test. Connector _ test. Comma, test. Semicolon; test. Colon: test. Slash / test. Slash \ test.";

string[] patterns = { 
    @"(^|\p{P}\s+)(\w+)", // all punctuation chars
    @"(^|[\p{P}-[\p{Pc}\p{Pd}\p{Ps}\p{Pe}]]\s+)(\w+)", // all punctuation chars except Pc/Pd/Ps/Pe
    @"(^|[\p{P}-[\p{Po}]]\s+)(\w+)" // all punctuation chars except Po
};

// compiled for performance (might want to benchmark it for your loop)
foreach (string pattern in patterns)
{
    Console.WriteLine("*** Current pattern: {0}", pattern);
    string result = Regex.Replace(input, pattern,
                            m => m.Groups[1].Value
                                 + m.Groups[2].Value.Substring(0, 1).ToUpper()
                                 + m.Groups[2].Value.Substring(1));
    Console.WriteLine(result);
    Console.WriteLine();
}

Обратите внимание, что «Dash» не используется с использованием последнего шаблона, и он находится на новой линии. Один из способов сделать его заглавным - это использовать RegexOptions.Multiline вариант. Попробуйте приведенный выше фрагмент, чтобы увидеть, соответствует ли он вашему желаемому результату.

Кроме того, для примера я не использовал regexoptions.compiled в вышеупомянутом цикле. Использовать оба варианта или их вместе: RegexOptions.Compiled | RegexOptions.Multiline.

Создайте отдельные разделы в представлении для реквизитов покупки и результатов ставок.Что-то вроде этого:

<form action="" method="post" enctype="multipart/form-data">

  <h3>Purchase Requistions</h3>
  <label for="file1">Filename:</label>
  <input type="file" name="purchasereqs" id="file1" />

  <label for="file2">Filename:</label>
  <input type="file" name="purchasereqs" id="file2" />

  <h3>Bid Results</h3>
  <label for="file3">Filename:</label>
  <input type="file" name="bidresults" id="file3" />

  <label for="file4">Filename:</label>
  <input type="file" name="bidresults" id="file4" />

  <input type="submit"  />
</form>
.

Тогда у вас будет подпись действий:

[HttpPost]
public ActionResult Create(
  TransactionViewModel model, 
  IEnumerable<HttpPostedFileBase> purchasereqs,
  IEnumerable<HttpPostedFileBase> bidresults)
{ 
   //save to database 
}
.

Я не знаю почему, но я решил дать доходность возврата Попытка, основываясь на том, что предложил Лбушкин. Просто для развлечения.

static IEnumerable<char> CapitalLetters(string sentence)
        {
            //capitalize first letter
            bool capitalize = true;
            char lastLetter;
            for (int i = 0; i < sentence.Length; i++)
            {
                lastLetter = sentence[i];
                yield return (capitalize) ? Char.ToUpper(sentence[i]) : sentence[i];


                if (Char.IsWhiteSpace(lastLetter) && capitalize == true)
                    continue;

                capitalize = false;
                if (lastLetter == '.' || lastLetter == '!') //etc
                    capitalize = true;
            }
        }

Чтобы использовать его:

string sentence = new String(CapitalLetters("this is some code. the code is in C#.").ToArray());
  1. Сделайте свою работу в StringBuffer.
  2. Строчный все это.
  3. Перевернуть и ведущий ведущий Chars.
  4. Позвоните ToString.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top