我有一个带有文本框的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的答案。


当前回答

由于这个问题是关于最大化性能的,我采用了Darren的版本来使用跨度,这减少了垃圾,并提高了大约10%的速度。

/// <summary>
/// Returns the input string with the first character converted to uppercase
/// </summary>
public static string ToUpperFirst(this string s)
{
    if (string.IsNullOrEmpty(s))
        throw new ArgumentException("There is no first letter");

    Span<char> a = stackalloc char[s.Length];
    s.AsSpan(1).CopyTo(a.Slice(1));
    a[0] = char.ToUpper(s[0]);
    return new string(a);
}

性能

Method Data Mean Error StdDev
Carlos red 107.29 ns 2.2401 ns 3.9234 ns
Darren red 30.93 ns 0.9228 ns 0.8632 ns
Marcell red 26.99 ns 0.3902 ns 0.3459 ns
Carlos red house 106.78 ns 1.9713 ns 1.8439 ns
Darren red house 32.49 ns 0.4253 ns 0.3978 ns
Marcell red house 27.37 ns 0.3888 ns 0.3637 ns

完整的测试代码

using System;
using System.Linq;

using BenchmarkDotNet.Attributes;

namespace CorePerformanceTest
{
    public class StringUpperTest
    {
        [Params("red", "red house")]
        public string Data;

        [Benchmark]
        public string Carlos() => Data.Carlos();

        [Benchmark]
        public string Darren() => Data.Darren();

        [Benchmark]
        public string Marcell() => Data.Marcell();
    }

    internal static class StringExtensions
    {
        public static string Carlos(this string input) =>
            input switch
            {
                null => throw new ArgumentNullException(nameof(input)),
                "" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)),
                _ => input.First().ToString().ToUpper() + input.Substring(1)
            };

        public static string Darren(this string s)
        {
            if (string.IsNullOrEmpty(s))
                throw new ArgumentException("There is no first letter");

            char[] a = s.ToCharArray();
            a[0] = char.ToUpper(a[0]);
            return new string(a);
        }

        public static string Marcell(this string s)
        {
            if (string.IsNullOrEmpty(s))
                throw new ArgumentException("There is no first letter");

            Span<char> a = stackalloc char[s.Length];
            s.AsSpan(1).CopyTo(a.Slice(1));
            a[0] = char.ToUpper(s[0]);
            return new string(a);
        }
    }

}

其他回答

最快的方法:

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个符号作为输入的字符串):

测试结果

正如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);
}

我想提供一个“最大性能”的答案。在我看来,“最大性能”的答案抓住了所有的场景,并提供了解释这些场景的问题的答案。所以,这是我的答案。原因如下:

IsNullOrWhiteSpace accounts for strings that are just spaces or null/empty. .Trim() removes white space from the front and back of the string. .First() takes the first element of an IEnumerable<TSource> (or string). We should check to see if it is a letter that can/should be uppercase. We then add the rest of the string, only if the length indicates we should. By .NET best practice, we should provide a culture under System.Globalization.CultureInfo. Providing them as optional parameters makes this method totally reusable, without having to type the chosen culture every time. I also noticed that my and most of these answers did not maintain the whitespace at the beginning of the string. This will also show how to maintain that whitespace. //Capitalize the first letter disregard all chars using regex. public static string RegCapString(this string instring, string culture = "en-US", bool useSystem = false) { if (string.IsNullOrWhiteSpace(instring)) { return instring; } var m = Regex.Match(instring, "[A-Za-z]").Index; return instring.Substring(0, m) + instring[m].ToString().ToUpper(new CultureInfo(culture, useSystem)) + instring.Substring(m + 1); } //Capitalize first char if it is a letter disregard white space. public static string CapString(this string instring, string culture = "en-US", bool useSystem = false) { if (string.IsNullOrWhiteSpace(instring) || !char.IsLetter(instring.Trim().First())) { return instring; } var whiteSpaces = instring.Length - instring.TrimStart().Length; return (new string(' ', whiteSpaces)) + instring.Trim().First().ToString().ToUpper(new CultureInfo(culture, useSystem)) + ((instring.TrimStart().Length > 1) ? instring.Substring(whiteSpaces + 1) : ""); }

我用这个来纠正名字。它的基本原理是,如果字符遵循特定的模式,则将其更改为大写。在这种情况下,我选择了空格和“Mc”的破折号。

private String CorrectName(String name)
{
    List<String> StringsToCapitalizeAfter = new List<String>() { " ", "-", "Mc" };
    StringBuilder NameBuilder = new StringBuilder();
    name.Select(c => c.ToString()).ToList().ForEach(c =>
    {
        c = c.ToLower();
        StringsToCapitalizeAfter.ForEach(s =>
        {
            if(String.IsNullOrEmpty(NameBuilder.ToString()) ||
               NameBuilder.ToString().EndsWith(s))
            {
                c = c.ToUpper();
            }
        });
        NameBuilder.Append(c);
    });
    return NameBuilder.ToString();
}

解决问题的可能方法:

   public static string FirstToUpper(this string lowerWord)
   {
       if (string.IsNullOrWhiteSpace(lowerWord) || string.IsNullOrEmpty(lowerWord))
            return lowerWord;
       return new StringBuilder(lowerWord.Substring(0, 1).ToUpper())
                 .Append(lowerWord.Substring(1))
                 .ToString();
   }