我有一个带有文本框的DetailsView 我希望输入的数据总是以大写的第一个字母保存。

例子:

"red" --> "Red"
"red house" --> " Red house"

我怎样才能实现性能最大化呢?


注意:

Based on the answers and the comments under the answers, many people think this is asking about capitalizing all words in the string. E.g. => Red House It isn't, but if that is what you seek, look for one of the answers that uses TextInfo's ToTitleCase method. (Note: Those answers are incorrect for the question actually asked.) See TextInfo.ToTitleCase documentation for caveats (doesn't touch all-caps words - they are considered acronyms; may lowercase letters in middle of words that "shouldn't" be lowered, e.g., "McDonald" → "Mcdonald"; not guaranteed to handle all culture-specific subtleties re capitalization rules.)


注意:

第一个字母之后的字母是否必须小写,这个问题很模糊。公认的答案假定只有第一个字母需要修改。如果要强制字符串中除第一个字母外的所有字母都小写,请查找包含ToLower且不包含ToTitleCase的答案。


当前回答

最快的方法:

private string Capitalize(string s){
    if (string.IsNullOrEmpty(s))
    {
        return string.Empty;
    }
    char[] a = s.ToCharArray();
    a[0] = char.ToUpper(a[0]);
    return new string(a);
}

测试显示下一个结果(有1,000,000个符号作为输入的字符串):

测试结果

其他回答

下面是对我有用的代码:

private string StringLetterUppercase(string input)
{
    if (input == null)
    {
        throw new ArgumentNullException(nameof(input));
    }
    else if (input == "")
    {
        throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input));
    }
    else
    {
        return input.First().ToString().ToUpper() + input.Substring(1);
    }
}

正如BobBeechey在回答这个问题时所建议的,下面的代码可以解决这个问题:

private void txt_fname_TextChanged(object sender, EventArgs e)
{
    char[] c = txt_fname.Text.ToCharArray();
    int j;
    for (j = 0; j < txt_fname.Text.Length; j++)
    {
        if (j==0) c[j]=c[j].ToString().ToUpper()[0];
        else c[j] = c[j].ToString().ToLower()[0];
    }
    txt_fname.Text = new string(c); 
    txt_fname.Select(txt_fname.Text.Length, 1);
}

试试这个:

static public string UpperCaseFirstCharacter(this string text) {
    return Regex.Replace(text, "^[a-z]", m => m.Value.ToUpper());
}

最近我有一个类似的需求,并记得LINQ函数Select()提供了一个索引:

string input;
string output;

input = "red house";
output = String.Concat(input.Select((currentChar, index) => index == 0 ? Char.ToUpper(currentChar) : currentChar));
//output = "Red house"

因为我经常需要它,所以我为字符串类型做了一个扩展方法:

public static class StringExtensions
{
    public static string FirstLetterToUpper(this string input)
    {
        if (string.IsNullOrEmpty(input))
            return string.Empty;
        return String.Concat(input.Select((currentChar, index) => index == 0 ? Char.ToUpper(currentChar) : currentChar));
    }
}

请注意,只有第一个字母被转换为大写字母,其余所有字符都不会被更改。如果你需要其他字符小写,你也可以为索引> 0调用Char.ToLower(currentChar),或者首先在整个字符串上调用ToLower()。

关于性能,我将代码与Darren的解决方案进行了比较。在我的机器上,Darren的代码大约快了两倍,这并不奇怪,因为他只直接编辑char数组中的第一个字母。

所以我建议你采用达伦的代码,如果你需要最快的解决方案。如果您想集成其他字符串操作,那么让lambda函数的表达能力触及输入字符串的字符可能会很方便——您可以轻松地扩展这个函数——所以我把这个解决方案留在这里。

我们可以这样做(c# 8.0, .NET 5):

input?.Length > 0 ? char.ToUpperInvariant(input[0]) + input[1..] : input

我相信这足够短,可以做内联。


如果input是一个空字符串,我们得到一个空字符串。如果input为null,则得到null。

否则,代码接受第一个字符输入[0],并使用char.ToUpperInvariant将其转换为大写。并连接其余的输入[1..]。

编译器会将范围访问转换为对Substring的调用,而且它可以利用我们已经获得了长度的事实。

与公认的答案相比,这样做的优点是不使用LINQ。其他一些答案将字符串转换为数组,只取第一个字符。这段代码也没有做到这一点。


如果你喜欢扩展方法,你可以这样做:

public static string FirstCharToUpper(this string input) =>
        input?.Length > 0 ? char.ToUpperInvariant(input[0]) + input[1..] : input;

如果你更喜欢扔呢?好的,让它扔:

public static string FirstCharToUpper(this string input) =>
        input switch
        {
            null => throw new ArgumentNullException(nameof(input)),
            _ => input.Length > 0 ? char.ToUpperInvariant(input[0]) + input[1..] : input
        };

这里是大致相同的代码(因为我们正在创建一个扩展方法,所以我们可以更详细一点):

public static string FirstCharToUpperEquivalent(this string input)
{
    if (input == null)
    {
        throw new ArgumentNullException(nameof(input));
    }

    var length = input.Length;
    if (length == 0)
    {
        return input;
    }

    string firstCharacter = char.ToUpperInvariant(input[0]).ToString();
    return string.Concat(firstCharacter, input.Substring(1, length - 1));
}

我做了1000轮155个单词的基准测试(所以它们被调用了155000次),结果是:

Benchmarking type Tests
  TestAccepted         00:00:00.0465979
  TestProposalNoThrow  00:00:00.0092839
  TestProposalDoThrow  00:00:00.0092938
  TestProposalEquival  00:00:00.0091463

我在Windows 10、英特尔酷睿i3上运行它,使用Jon Skeet用c#编写的简单微基准测试代码。