Заглавные слова в строке с использованием c#

Мне нужно взять строку и заглавными словами в ней. Некоторые слова ("in", " at " и т. д.), не капитализируются и изменяются на нижний регистр, если встречаются. Первое слово всегда должно быть заглавной буквой. Фамилии, такие как "McFly", не находятся в текущей области, поэтому к ним будет применяться то же правило - только первая буква с заглавной буквы.

например: "мышей и мужчин CNN "следует изменить на"мышей и мужчин CNN". (поэтому ToTitleString не будет работать вот!--4-->)

Мне интересно, что было бы лучшим способом сделать это. Я подумал о том, чтобы разбить строку на пробелы и пройтись по каждому слову, при необходимости изменяя его, связывая с предыдущим словом и так далее. Это кажется довольно наивным, и мне было интересно, есть ли лучший способ сделать это, используя .Net 3.5.

10 ответов


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

Edit:

вы можете сделать это с двумя проходами, используя regexes

var result = Regex.Replace("of mice and men isn't By CNN", @"\b(\w)", m => m.Value.ToUpper());
result = Regex.Replace(result, @"(\s(of|in|by|and)|\'[st])\b", m => m.Value.ToLower(), RegexOptions.IgnoreCase);

выводит Of Mice and Men Isn't by CNN.

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

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


использовать

Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase("of mice and men By CNN");

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


здесь ответ Как заработать именами

CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;

Console.WriteLine(textInfo.ToTitleCase(title));
Console.WriteLine(textInfo.ToLower(title));
Console.WriteLine(textInfo.ToUpper(title));

почему бы не использовать ToTitleCase() сначала, а затем сохранить список применимых слов и Replace вернуться к строчной версии этих применимых слов (при условии, что список небольшой).

Список применимых слов может быть сохранен в словаре и зациклен довольно эффективно, заменяя .ToLower() эквивалентны.


попробуйте что-то вроде этого:

public static string TitleCase(string input, params string[] dontCapitalize) {
   var split = input.Split(' ');
   for(int i = 0; i < split.Length; i++)
        split[i] = i == 0 
          ? CapitalizeWord(split[i]) 
          : dontCapitalize.Contains(split[i])
             ? split[i]
             : CapitalizeWord(split[i]);
   return string.Join(" ", split);
}
public static string CapitalizeWord(string word)
{
    return char.ToUpper(word[0]) + word.Substring(1);
}

вы можете позже обновить CapitalizeWord метод, если вам нужно обрабатывать сложные фамилии. Добавьте эти методы в класс и используйте его следующим образом:

SomeClass.TitleCase("a test is a sentence", "is", "a"); // returns "A Test is a Sentence"

вы можете иметь словарь, имеющий слова, которые вы хотели бы игнорировать, разделить предложение на фразы (.split ( '' )) и для каждой фразы проверьте, существует ли фраза в словаре, если нет, заглавной буквы первого символа, а затем добавьте строку в буфер строк. Если фраза, которую вы сейчас обрабатываете, находится в словаре, просто добавьте ее в буфер строк.


небольшое улучшение ответа Джонни:

var result = Regex.Replace(s.Trim(), @"\b(\w)", m => m.Value.ToUpper());
        result = Regex.Replace(result, @"\s(of|in|by|and)\s", m => m.Value.ToLower(), RegexOptions.IgnoreCase);
        result = result.Replace("'S", "'s");

вы должны создать свою собственную функцию, как вы описываете.


неумный подход, который обрабатывает простой случай:

var s = "of mice and men By CNN";
var sa = s.Split(' ');
for (var i = 0; i < sa.Length; i++)
    sa[i] = sa[i].Substring(0, 1).ToUpper() + sa[i].Substring(1);
var sout = string.Join(" ", sa);
Console.WriteLine(sout);

самым простым очевидным решением (для английских предложений) было бы:

  • "sentence".Split(" ") предложение о пробелах
  • цикл через каждый элемент
  • заглавная первая буква каждого элемента -item[i][0].ToUpper(),
  • вернитесь в строку, соединенную с пробелом.
  • повторите этот процесс с "."и", " используя эту новую строку.