麦当劳在 C 中为 ProperCase#

mcdonalds to ProperCase in C#

提问人:ob213 提问时间:9/25/2009 最后编辑:Mark Ruckerob213 更新时间:8/25/2017 访问量:5328

问:

如何在 C# 中将名称转换为正确的大小写?

我有一个名字列表,我想证明。

例如:麦当劳到麦当劳或奥布莱恩到奥布莱恩。

C# 字符串

评论

0赞 Jay Riggs 9/25/2009
这是一个有趣的问题。我不认为有“开箱即用”的解决方案。我已经为以下文章添加了书签,这些文章可能接近您想要的: 失物招领 正确大小写格式提供程序(IFormatProvider 实现) 我还没有尝试过代码,这个解决方案几乎需要手动处理所有情况。但这只是一个开始,也许你会发现它很有用。

答:

7赞 Gregory Higley 9/25/2009 #1

计算机绝对不可能神奇地知道“麦当劳”中的第一个“D”应该大写。所以,我认为有两种选择。

  1. 有人可能有一个软件或库可以为你做这件事。

  2. 除此之外,您唯一的选择是采用以下方法:首先,我会在具有“有趣”大写的单词字典中查找名称。显然,你必须自己提供这本词典,除非已经存在。其次,应用一种算法来纠正一些明显的错误,例如以 O' 开头的凯尔特人名字、Mac 和 Mc,尽管给定足够大的名字池,这样的算法无疑会有很多误报。最后,将不符合前两个条件的每个名称的首字母大写。

评论

7赞 Maciej Trybiło 11/29/2012
请不要对“Mac”进行虚拟方法。我的名字经常被愚蠢的邮件系统所残害。
7赞 supercat 8/3/2013
@MaciejTrybi ło:MacHines会这样做的。
1赞 Brian 9/25/2009 #2

其中最难的部分是决定大写的算法。字符串操作本身非常简单。没有完美的方法,因为案件没有“规则”。一种策略可能是一组规则,例如“将第一个字母大写......通常“和”如果前两个字母是 MC...通常”

从真实姓名词典开始,并将它们与您自己的名字进行比较以进行匹配会有所帮助。您还可以获取真实姓名字典,从中生成 Markhov 链,并将任何新名称扔给 Markhov 链以确定大小写。这是一个疯狂而复杂的解决方案。

最终的完美解决方案是使用人工来校正数据。

0赞 JaredPar 9/25/2009 #3

这样做要求你的程序能够在一定程度上解释英语。至少能够将一个字符串分解成一组单词。.Net Framework 中没有内置的 API 可以实现此目的。

但是,如果有,则可以使用以下代码。

public string ProperCase(string str, Func<string,bool> isWord) {
  var word = new StringBuilder();
  var cur = new StringBuilder();
  for ( var i = 0; i < str.Length; i++ ) {
    cur.Append(cur.Length == 0 ? Char.ToUpper(str[i]) : str[i]));
    if ( isWord(cur.ToString()) {
      word.Append(cur.ToString());
      cur.Length = 0;
    }
  }
  if ( cur.Length > 0 ) {
    word.Append(cur);
  }
  return word.ToString();
}

这不是一个完美的解决方案,但它可以让您大致了解大纲

9赞 tster 9/25/2009 #4

您可以考虑使用搜索引擎来帮助您。提交查询,查看结果如何将名称大写。

评论

3赞 tster 9/25/2009
我从来没有真正做过。听起来像是新实习生的任务!
8赞 Eddie Velasquez 9/25/2009 #5

我写了以下扩展方法。随意使用它们。

public static class StringExtensions
{
  public static string ToProperCase( this string original )
  {
    if( original.IsNullOrEmpty() )
      return original;

    string result = _properNameRx.Replace( original.ToLower( CultureInfo.CurrentCulture ), HandleWord );
    return result;
  }

  public static string WordToProperCase( this string word )
  {
    if( word.IsNullOrEmpty() )
      return word;

    if( word.Length > 1 )
      return Char.ToUpper( word[0], CultureInfo.CurrentCulture ) + word.Substring( 1 );

    return word.ToUpper( CultureInfo.CurrentCulture );
  }

  private static readonly Regex _properNameRx = new Regex( @"\b(\w+)\b" );

  private static readonly string[] _prefixes = { "mc" };

  private static string HandleWord( Match m )
  {
    string word = m.Groups[1].Value;

    foreach( string prefix in _prefixes )
    {
      if( word.StartsWith( prefix, StringComparison.CurrentCultureIgnoreCase ) )
        return prefix.WordToProperCase() + word.Substring( prefix.Length ).WordToProperCase();
    }

    return word.WordToProperCase();
  }
}

评论

1赞 Lukas 10/18/2019
你真棒!谢谢!
0赞 Lee 9/25/2009 #6

您可以根据包含正确大小写大小写的字典(文件)检查小写/混合大小写的姓氏,然后从字典中返回“真实”值。

我快速谷歌了一下,看看是否存在,但无济于事!

评论

1赞 Lee 9/25/2009
哎呀,刚刚注意到格雷戈里说了同样的话,并提出了额外的(和有用的)观察结果。我优雅地鞠躬:]
-2赞 Sam Marshall 5/4/2010 #7
CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;
string txt = textInfo.ToTitleCase("texthere");

评论

0赞 Bono 11/21/2015
虽然此代码可以回答问题,但提供有关此代码为何和/或如何回答问题的其他上下文可以提高其长期价值。
0赞 Lukas 10/18/2019
这并不能解决“Mc”情况。标题大小写将使其成为“麦当劳”而不是“麦当劳”
0赞 Tracker1 1/7/2011 #8

我打算编写这样的函数,但可能不会涉及太多边缘情况......下面在带有正则表达式的伪装代码中进行匹配......

以 /\b[A-Z]+\b/ 开头作为集合匹配,因此每个字母序列对着一个单词边界,匹配为一个集合。

if the string is all uppercase...
  lower-case the string
  upper-case the first letter
  do the following beginning of string replacements
    Vanb -> VanB
    Vanh -> VanH
    Mc? -> Mc?  (uppercase wildcard character)
    Mac[^kh] -> Mac? (uppercase wildcard match)

使用替换的全名字符串,与其他替换集进行匹配,例如...

"De La " -> "de la "

这应该能抓住大多数情况,尤其是名字......但是一个不错的通用名称大小写数据库会非常好。

0赞 Klyph 8/25/2017 #9

这是我的解决方案。这会将名称硬编码到程序中,但只需稍加工作,您就可以在程序外部保留一个文本文件,并读取名称例外(即 Van、Mc、Mac)并循环访问它们。

public static String toProperName(String name)
{
    if (name != null)
    {
        if (name.Length >= 2 && name.ToLower().Substring(0, 2) == "mc")  // Changes mcdonald to "McDonald"
            return "Mc" + Regex.Replace(name.ToLower().Substring(2), @"\b[a-z]", m => m.Value.ToUpper());

        if (name.Length >= 3 && name.ToLower().Substring(0, 3) == "van")  // Changes vanwinkle to "VanWinkle"
            return "Van" + Regex.Replace(name.ToLower().Substring(3), @"\b[a-z]", m => m.Value.ToUpper());

        return Regex.Replace(name.ToLower(), @"\b[a-z]", m => m.Value.ToUpper());  // Changes to title case but also fixes 
                                                                                   // appostrophes like O'HARE or o'hare to O'Hare
    }

    return "";
}