制作字符串大写的第一个字母(具有最大性能)

412 c# performance

我有DetailsView一个TextBox 和我想要的输入数据始终保存的第一个字母注册资本.

例:

"red" --> "Red"
"red house" --> " Red house"
Run Code Online (Sandbox Code Playgroud)

如何实现这种最大化的性能


注意:
根据答案和答案下的评论,很多人认为这是在询问字符串中所有单词的大写.例如,=> Red House 它不是,但如果这是你所追求的,寻找使用其中一个答案TextInfoToTitleCase方法.(注意:对于实际提出的问题,这些答案是不正确的.)
请参阅TextInfo.ToTitleCase doc以获取警告(不触及所有大写单词 - 它们被视为首字母缩略词;可以在"不应该"的单词中间小写字母降低,例如"麦当劳"=>"麦当劳";不保证能够处理所有特定文化的细微差别.


注意:
关于第一个字母之后的字母是否应该强制小写,问题不明确.接受的答案假定只应改变第一个字母.如果要强制除第一个字符串之外的字符串中的所有字母都是小写,请查找包含但不包含ToTitleCase的答案.ToLower

Car*_*ñoz 524

编辑:更新为更新的语法(和更正确的答案),也作为扩展方法.

public static class StringExtensions
{
    public static string FirstCharToUpper(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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

老答复

public static class StringExtensions
{
    public static string FirstCharToUpper(this string input)
    {
        switch (input)
        {
            case null: throw new ArgumentNullException(nameof(input));
            case "": throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input));
            default: return input.First().ToString().ToUpper() + input.Substring(1);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:这个版本更短.如需更快的解决方案,请查看Equiso的答案

public static string FirstCharToUpper(string input)
{
    if (String.IsNullOrEmpty(input))
        throw new ArgumentException("ARGH!");
    return input.First().ToString().ToUpper() + String.Join("", input.Skip(1));
}
Run Code Online (Sandbox Code Playgroud)

编辑2:可能最快的解决方案是Darren(甚至还有一个基准),虽然我会更改它的string.IsNullOrEmpty(s)验证以抛出异常,因为原始要求期望第一个字母存在,因此它可以是大写的.请注意,此代码适用于通用字符串,而不是特别适用于来自的有效值Textbox.

  • 我非常喜欢你的答案,但是`var arr = input.ToCharArray(); arr [0] = Char.ToUpperInvariant(arr [0]); 返回new String(arr);`可能会获得一些速度,因为你创建的不可变对象(特别是你正在跳过`String.Join`).这当然取决于字符串的长度. (25认同)
  • 嗯......从技术上讲,这应该回归"唉!"`以保持**大写第一封信**规则.;) (7认同)
  • 太棒了 - 使用Linq非常清楚这段代码的作用. (3认同)
  • 因为`String.Join`的第一个参数是分隔符,用它来连接用第二个参数给出的字符串. (2认同)
  • @ jp2code由于在空字符串或空字符串中大写不存在的第一个字母就好像被怀孕的海豚拍了一样,然后全部大写!是正确的拼写.http://www.urbandictionary.com/define.php?term=ARGH&defid=67839 (2认同)

Die*_*res 301

public string FirstLetterToUpper(string str)
{
    if (str == null)
        return null;

    if (str.Length > 1)
        return char.ToUpper(str[0]) + str.Substring(1);

    return str.ToUpper();
}
Run Code Online (Sandbox Code Playgroud)

旧答案:这使得每个第一个字母大写

public string ToTitleCase(string str)
{
    return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
}
Run Code Online (Sandbox Code Playgroud)

  • 他问"红房子"=​​>"红房子".ToTitleCase会给你"红屋". (14认同)

Pie*_*met 147

正确的方法是使用文化:

System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(word.ToLower())
Run Code Online (Sandbox Code Playgroud)

注意:这将大写字符串中的每个单词,例如"red house" - >"Red House".该解决方案还将在单词内进行小写大写,例如"老麦当劳" - >"老麦克唐纳".

  • 这是一个错误的答案,因为"红屋"成为"红屋"(注意"H")! (26认同)
  • 问题提出六年后,请更全面地了解*阅读现有答案及其评论*.如果您确信自己有更好的解决方案,那么*显示您的答案以您认为优越的方式表现的情况,特别是与现有答案的不同之处.1)Equiso在他的答案的后半部分已经涵盖了这个选项.2)在许多情况下,"ToLower"是一个错误,因为它消除了单词中间的大写,例如"麦当劳".3)问题是*只改变字符串的第一个单词*,**而不是**关于TitleCase. (21认同)
  • 我对此的问题是它将擦除中间字符串的潜在有效大写字母.例如McNames (12认同)
  • 这将输入转换为"标题案例" - 因此它将"红马"变成"红马" - 而有人明确表示不应该这样做(并返回"红马").这不是正确的方法. (9认同)
  • 这是最合适的方式,而不是重新发明轮子,并尝试编写自己的版本. (4认同)
  • 无论如何,良好的文化不会造成伤害。其他观看者可能没有“只有第一个字母”的要求。 (2认同)

Dar*_*ren 62

我从http://www.dotnetperls.com/uppercase-first-letter采用最快的方法并转换为扩展方法:

    /// <summary>
    /// Returns the input string with the first character converted to uppercase, or mutates any nulls passed into string.Empty
    /// </summary>
    public static string FirstLetterToUpperCaseOrConvertNullToEmptyString(this string s)
    {
        if (string.IsNullOrEmpty(s))
            return string.Empty;

        char[] a = s.ToCharArray();
        a[0] = char.ToUpper(a[0]);
        return new string(a);
    }
Run Code Online (Sandbox Code Playgroud)

注意:使用的原因ToCharArray比替代方法更快char.ToUpper(s[0]) + s.Substring(1),是只Substring分配了一个字符串,而方法为子字符串分配了一个字符串,然后是第二个字符串来组成最终结果.


编辑:这是这种方法的样子,结合CarlosMuñoz的初步测试,接受了答案:

    /// <summary>
    /// Returns the input string with the first character converted to uppercase
    /// </summary>
    public static string FirstLetterToUpperCase(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);
    }
Run Code Online (Sandbox Code Playgroud)

  • @CarlosMuñoz - 已经在元中讨论过是否“改进”其他人的答案。共识是“如果你可以改进答案,那就这样做——没有人‘拥有’答案,即使是原作者——目标是获得最好的答案”。您当然可以自由编辑或回滚编辑。在这种情况下,出于礼貌,原作者的版本将成为最终结果,我将满足于发表评论。通常我*也会*对我所做的更改发表评论;如果我没有这样做,我深表歉意。 (2认同)
  • 我对所有答案进行了基准测试,最后这个答案获胜了。更改为“char.ToUpperInvariant”甚至快了 20% (2认同)

İbr*_*lük 44

你可以使用"ToTitleCase方法"

string s = new CultureInfo("en-US").TextInfo.ToTitleCase("red house");
//result : Red House
Run Code Online (Sandbox Code Playgroud)

这种扩展方法解决了每个标题问题.

易于使用

string str = "red house";
str.ToTitleCase();
//result : Red house

string str = "red house";
str.ToTitleCase(TitleCase.All);
//result : Red House
Run Code Online (Sandbox Code Playgroud)

扩展方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace Test
{
    public static class StringHelper
    {
        private static CultureInfo ci = new CultureInfo("en-US");
        //Convert all first latter
        public static string ToTitleCase(this string str)
        {
            str = str.ToLower();
            var strArray = str.Split(' ');
            if (strArray.Length > 1)
            {
                strArray[0] = ci.TextInfo.ToTitleCase(strArray[0]);
                return string.Join(" ", strArray);
            }
            return ci.TextInfo.ToTitleCase(str);
        }
        public static string ToTitleCase(this string str, TitleCase tcase)
        {
            str = str.ToLower();
            switch (tcase)
            {
                case TitleCase.First:
                    var strArray = str.Split(' ');
                    if (strArray.Length > 1)
                    {
                        strArray[0] = ci.TextInfo.ToTitleCase(strArray[0]);
                        return string.Join(" ", strArray);
                    }
                    break;
                case TitleCase.All:
                    return ci.TextInfo.ToTitleCase(str);
                default:
                    break;
            }
            return ci.TextInfo.ToTitleCase(str);
        }
    }

    public enum TitleCase
    {
        First,
        All
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Tacttin它将工作,但下面的代码是更容易阅读和执行更好char.ToUpper(文本[0])+((text.Length> 1)text.Substring(1).ToLower():的String.Empty) ; 你可以阅读更多信息@ http://vkreynin.wordpress.com/2013/10/09/capitalize-only-first-character-c/ (3认同)
  • 您的解决方案的问题是“红房子”将转换为“红房子”,而不是问题中提出的“红房子”。 (2认同)
  • 我不喜欢这个解决方案,因为它将两种完全不同的情况组合成一种冗长的方法。我也没有看到概念上的好处。并且仅大写第一个字母的实现是..荒谬的。如果你想大写第一个字母,明显的实现是*大写(ToUpper)第一个字母*。取而代之的是,我将有两种不同的方法。Equiso 的答案(或 Guillernet 的新答案)中的“FirstLetterToUpper”和此处的“ToTitleCase”,但没有第二个参数。那么不需要`enum TitleCase`。 (2认同)

Kob*_*obi 31

对于第一个字母,进行错误检查:

public string CapitalizeFirstLetter(string s)
{
    if (String.IsNullOrEmpty(s))
        return s;
    if (s.Length == 1)
        return s.ToUpper();
    return s.Remove(1).ToUpper() + s.Substring(1);
}
Run Code Online (Sandbox Code Playgroud)

这里有一个方便的扩展

public static string CapitalizeFirstLetter(this string s)
    {
    if (String.IsNullOrEmpty(s)) return s;
    if (s.Length == 1) return s.ToUpper();
    return s.Remove(1).ToUpper() + s.Substring(1);
    }
Run Code Online (Sandbox Code Playgroud)


Tar*_*nin 11

public static string ToInvarianTitleCase(this string self)
{
    if (string.IsNullOrWhiteSpace(self))
    {
        return self;
    }

    return CultureInfo.InvariantCulture.TextInfo.ToTitleCase(self);
}
Run Code Online (Sandbox Code Playgroud)


l33*_*33t 11

使用string.Create()并避免throw在我们的方法中使用关键字(是的,您没看错),我们可以更进一步地使用Marcell 的答案。此外,我的方法处理任意长度的字符串(例如,几兆字节的文本)。

public static string L33t(this string s)
{
    static void ThrowError() => throw new ArgumentException("There is no first letter");

    if (string.IsNullOrEmpty(s))
        ThrowError();                      // No "throw" keyword to avoid costly IL

    return string.Create(s.Length, s, (chars, state) =>
    {
        state.AsSpan().CopyTo(chars);      // No slicing to save some CPU cycles
        chars[0] = char.ToUpper(chars[0]);
    });
}
Run Code Online (Sandbox Code Playgroud)

表现

以下是在.NET Core 3.1.7, 64 位上运行的基准测试的数字。我添加了一个更长的字符串来确定额外副本的成本。

方法 数据 意思 错误 标准差 中位数
L33t 红色的 8.545 纳秒 0.4612 纳秒 1.3308 纳秒 8.075 纳秒
马塞尔 红色的 9.153 纳秒 0.3377 纳秒 0.9471 纳秒 8.946 纳秒
L33t 红房子 7.715 纳秒 0.1741 纳秒 0.4618 纳秒 7.793 纳秒
马塞尔 红房子 10.537 纳秒 0.5002 纳秒 1.4351 纳秒 10.377 纳秒
L33t 红色 r(...)house [89] 11.121 纳秒 0.6774 纳秒 1.9106 纳秒 10.612 纳秒
马塞尔 红色 r(...)house [89] 16.739 纳秒 0.4468 纳秒 1.3033 纳秒 16.853 纳秒

完整的测试代码

using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace CorePerformanceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<StringUpperTest>();
        }
    }

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

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

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

    internal static class StringExtensions
    {
        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);
        }

        public static string L33t(this string s)
        {
            static void ThrowError() => throw new ArgumentException("There is no first letter");

            if (string.IsNullOrEmpty(s))
                ThrowError(); // IMPORTANT: Do not "throw" here!

            return string.Create(s.Length, s, (chars, state) =>
            {
                state.AsSpan().CopyTo(chars);
                chars[0] = char.ToUpper(chars[0]);
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请让我知道你是否可以让它更快!

  • 您*可以*使用“throw”关键字,但它的存在本身就会阻止某些编译器优化,例如内联。您可以在有或没有它的情况下运行示例,您会发现它确实会影响性能。 (2认同)

小智 9

最快的方法:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

检测结果

  • 我建议在 null 或空时返回 `s` 参数。 (3认同)

Mar*_*oth 8

由于这个问题是关于最大化性能,我采用了达伦的版本使用Spans,减少了垃圾并提高了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);
}
Run Code Online (Sandbox Code Playgroud)

表现

方法 数据 意思 错误 标准差
卡洛斯 红色的 107.29 纳秒 2.2401 纳秒 3.9234 纳秒
达伦 红色的 30.93 纳秒 0.9228 纳秒 0.8632 纳秒
马塞尔 红色的 26.99 纳秒 0.3902 纳秒 0.3459 纳秒
卡洛斯 红房子 106.78 纳秒 1.9713 纳秒 1.8439 纳秒
达伦 红房子 32.49 纳秒 0.4253 纳秒 0.3978 纳秒
马塞尔 红房子 27.37 纳秒 0.3888 纳秒 0.3637 纳秒

完整的测试代码

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

}
Run Code Online (Sandbox Code Playgroud)

  • 您可能应该防范超长字符串。如果你有超过大约 1MB 的字符,`stackalloc` 将破坏堆栈。 (2认同)

Joe*_*Fan 6

尝试这个:

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

  • 或者可能是其他一些字符类(即字母数字 \w),以便该函数能够识别 unicode (2认同)

小智 6

如果性能/内存使用是一个问题,那么这个只创建一(1)个StringBuilder和一(1)个与原始字符串大小相同的新String.

public static string ToUpperFirst(this string str) {
  if( !string.IsNullOrEmpty( str ) ) {
    StringBuilder sb = new StringBuilder(str);
    sb[0] = char.ToUpper(sb[0]);

    return sb.ToString();

  } else return str;
}
Run Code Online (Sandbox Code Playgroud)

  • 这可以通过简单的`char []`来完成,而不是让`StringBuilder`的所有基础结构包装它.而不是`new StringBuilder(str)`,使用`str.ToCharArray()`,而不是`sb.ToString()`,使用`new string(charArray)`.`StringBuilder`模拟字符数组本身公开的索引类型,因此实际的`.ToUpper`行可以基本相同.:-) (3认同)

CAO*_*ley 6

由于我碰巧也在做这方面的工作,并且正在四处寻找任何想法,这就是我找到的解决方案。它使用 LINQ,并且能够将字符串的第一个字母大写,即使第一次出现的不是字母。这是我最终制作的扩展方法。

public static string CaptalizeFirstLetter(this string data)
{
    var chars = data.ToCharArray();

    // Find the Index of the first letter
    var charac = data.First(char.IsLetter);
    var i = data.IndexOf(charac);

    // capitalize that letter
    chars[i] = char.ToUpper(chars[i]);

    return new string(chars);
}
Run Code Online (Sandbox Code Playgroud)

我相信有一种方法可以稍微优化或清理它。


小智 6

如果您只关心第一个字母是否大写,而字符串的其余部分无关紧要,则只需选择第一个字符,将其设为大写,然后将其与没有原始第一个字符的字符串的其余部分连接起来。

String word ="red house";
word = word[0].ToString().ToUpper() + word.Substring(1, word.length -1);
//result: word = "Red house"
Run Code Online (Sandbox Code Playgroud)

我们需要将第一个字符转换成ToString(),因为我们是把它读成一个Char数组,而Char类型没有ToUpper()方法。


mba*_*per 6

检查字符串是否不为空,将第一个字符转换为大写,其余字符转换为小写:

public static string FirstCharToUpper(string str)
{
    return str?.First().ToString().ToUpper() + str?.Substring(1).ToLower();
}
Run Code Online (Sandbox Code Playgroud)


bin*_*les 5

这是一种作为扩展方法来执行此操作的方法:

static public string UpperCaseFirstCharacter(this string text)
{
    if (!string.IsNullOrEmpty(text))
    {
        return string.Format(
            "{0}{1}",
            text.Substring(0, 1).ToUpper(),
            text.Substring(1));
    }

    return text;
}
Run Code Online (Sandbox Code Playgroud)

然后可以这样调用它:

//yields "This is Brian's test.":
"this is Brian's test.".UpperCaseFirstCharacter();
Run Code Online (Sandbox Code Playgroud)

这是它的一些单元测试:

[Test]
public void UpperCaseFirstCharacter_ZeroLength_ReturnsOriginal()
{
    string orig = "";
    string result = orig.UpperCaseFirstCharacter();

    Assert.AreEqual(orig, result);
}

[Test]
public void UpperCaseFirstCharacter_SingleCharacter_ReturnsCapital()
{
    string orig = "c";
    string result = orig.UpperCaseFirstCharacter();

    Assert.AreEqual("C", result);
}

[Test]
public void UpperCaseFirstCharacter_StandardInput_CapitalizeOnlyFirstLetter()
{
    string orig = "this is Brian's test.";
    string result = orig.UpperCaseFirstCharacter();

    Assert.AreEqual("This is Brian's test.", result);
}
Run Code Online (Sandbox Code Playgroud)


xam*_*mir 5

我在C# 大写首字母 - Dot Net Perls中发现了一些内容:

static string UppercaseFirst(string s)
{
    // Check for empty string.
    if (string.IsNullOrEmpty(s))
    {
        return string.Empty;
    }

    // Return char and concat substring.
    return char.ToUpper(s[0]) + s.Substring(1);
}
Run Code Online (Sandbox Code Playgroud)

  • 与 Equiso 4 年前的答案相比,这有何改进? (2认同)