ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个带有 TextBoxDetailsView,我希望 输入数据始终保存,并使用 首字母大写

例子:

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

我怎样才能实现这种最大化的性能?

笔记:

根据答案和答案下的评论,许多人认为这是在询问字符串中的 all 单词是否大写。例如 => Red House 不是,但如果这是您所寻求的,请寻找使用 TextInfoToTitleCase 方法的答案之一。 (注意:对于实际提出的问题,这些答案不正确。)请参阅 TextInfo.ToTitleCase documentation 以了解警告(不涉及全大写单词 - 它们被视为首字母缩略词;可能会在单词中间出现小写字母“不应该”被降低,例如,“McDonald”→“Mcdonald”;不保证能处理所有特定文化的细微差别重新大写规则。)

笔记:

关于第一个字母之后的字母是否应该强制小写,问题是不明确。接受的答案假定只应更改第一个字母。如果您想强制字符串中除第一个以外的所有字母为小写,请查找包含 ToLower不包含 ToTitleCase 的答案。

@Bobby:这不是重复的:OP要求将字符串的第一个字母大写,链接中的问题将每个单词的第一个字母大写。
@GvS:第一个答案非常详细,第一个代码块正是他正在寻找的。此外,在大写每个单词和仅第一个单词之间只是一个循环差异。
但是你说,我引用,“使每个单词的第一个字母大写”。因此,为什么是“红房子”-->“红房子”?为什么“house”的“h”不是大写字母?
不要忘记假设您使用的是计算机,您可以这样做:stackoverflow.com/a/1206029/294884
@Fattie - 有用的链接,但是这个问题不是关于大写每个单词 - 它只是将字符串的第一个字母更改为大写字母。

C
Carlos Muñoz

不同C#版本的解决方案

至少具有 .NET Core 3.0 或 .NET Standard 2.1 的 C# 8

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)),
            _ => string.Concat(input[0].ToString().ToUpper(), input.AsSpan(1))
        };
}

由于 .NET Core 3.0 / .NET Standard 2.1 String.Concat() 支持 ReadonlySpan<char>,如果我们使用 .AsSpan(1) 而不是 .Substring(1),则可以节省一次分配。

C# 8

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[0].ToString().ToUpper() + input.Substring(1)
        };
}

C# 7

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[0].ToString().ToUpper() + input.Substring(1);
        }
    }
}

真的很老的答案

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

这个版本较短。如需更快的解决方案,请查看 Diego's answer

public static string FirstCharToUpper(string input)
{
    if (String.IsNullOrEmpty(input))
        throw new ArgumentException("ARGH!");
    return input.First().ToString().ToUpper() + input.Substring(1);
}

最快的解决方案可能是 Darren's(甚至还有一个基准),尽管我会更改它的 string.IsNullOrEmpty(s) 验证以引发异常,因为最初的要求期望第一个字母存在,因此它可以大写。请注意,此代码适用于通用字符串,而不适用于 Textbox 中的有效值。


因为 String.Join 的第一个参数是用于连接第二个参数给出的字符串的分隔符。
我真的很喜欢您的回答,但 var arr = input.ToCharArray(); arr[0] = Char.ToUpperInvariant(arr[0]); return new String(arr); 可能会提高一些速度,因为您创建的不可变对象较少(尤其是您正在跳过 String.Join)。这当然取决于字符串的长度。
太棒了 - 使用 Linq 可以非常清楚地知道这段代码的作用。
嗯...从技术上讲,这应该返回 "Argh!" 以符合 大写首字母 规则。 ;)
@jp2code 由于在空字符串或空字符串中将不存在的第一个字母大写就像被怀孕的海豚拍打一样,所以全大写啊!是正确的拼写。 urbandictionary.com/define.php?term=ARGH&defid=67839
D
Diego
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();
}

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

public string ToTitleCase(string str)
{
    return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
}

但这会将单词的每个第一个字母都转换为大写,而不仅仅是字符串的第一个字符。
@GvS,这就是问题要求您做的事情。
他问“红房子”=>“红房子”。 ToTitleCase 会给你“红房子”。
@GvS,是的,这就是为什么我说这是我的旧答案并将每个首字母都设为大写
对此不确定,但 char + string 会导致装箱。以防万一最大性能是要求。
A
AZ_

正确的方法是使用文化:

System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(word.ToLower())

注意:这会将字符串中的每个单词大写,例如“red house”->“Red House”。该解决方案还将单词中的小写字母大写,例如“old McDonald” --> “Old Mcdonald”。


在提出问题六年后,请更彻底地阅读现有答案及其评论。如果您确信自己有更好的解决方案,那么展示您的答案以您认为优越的方式表现的情况,特别是它与现有答案的不同之处。 1) Equiso 在他的回答的后半部分已经涵盖了这个选项。 2) 在许多情况下,ToLower 是错误的,因为它消除了单词中间的大写字母,例如“McDonalds”。 3) 问题是关于只改变字符串的第一个单词不是关于TitleCase。
无论如何,良好的文化不会受到伤害。其他查看者可能没有“唯一的首字母”要求。
一个同样正确的答案可能是 word.ToUpper() - 它将第一个字母更改为大写,我们不关心其余的。
“文化”是字面意思吗?
P
Peter Mortensen

我从 C# Uppercase First Letter - Dot Net Perls 中采用了最快的方法并转换为扩展方法:

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

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

结合来自 CarlosMuñoz's accepted answer 的初始测试,此方法如下所示:

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

哇,感谢您找到性能指标,展示性能卓越的解决方案!
@CarlosMuñoz - 它已在元中讨论过,是否“改进”其他人的答案。共识是“如果您可以改进答案,那么就这样做 - 没有人'拥有'答案,甚至原作者也没有 - 目标是获得最好的答案”。您当然可以自由编辑或回滚编辑。在这种情况下,一般的礼貌会让原作者的版本成为最终结果,我会接受评论。通常我也会对我所做的更改发表评论;如果我没有,我很抱歉。
达伦,我将通过@CarlosMuñoz 初始测试编辑您的答案以添加替代代码,以显示您的解决方案的外观。我相信您的贡献是找到了更高性能的解决方案,并且您不会介意此添加。如果您不喜欢它,请按照您认为适合我的编辑进行操作。
@ToolmakerSteve 同意理想情况下它不应该将 null 变为空字符串,但它对我的用例很方便,所以我将重命名原始方法。
我对所有答案进行了基准测试,这赢了。更改为 char.ToUpperInvariant 甚至快 20%
P
Peter Mortensen

您可以使用“ToTitleCase 方法”:

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

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

它很容易使用:

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

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

扩展方法:

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

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

对于第一个字母,带有错误检查:

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

这与方便的扩展相同

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

干净的方法。谢谢!
2
2 revs, 2 users 59%
public static string ToInvarianTitleCase(this string self)
{
    if (string.IsNullOrWhiteSpace(self))
    {
        return self;
    }

    return CultureInfo.InvariantCulture.TextInfo.ToTitleCase(self);
}

P
Peter Mortensen

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

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

表现

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

方法数据平均错误stddev中值L33T红色8.545 NS 0.4612 NS 1.3308 NS 8.075 NS MARCELL RED 9.153 NS 0.3377 NS 0.9471 NS 0.946 NS 8.946 NS 8.946 NS NS NS L33T L33T RED HOUSE 7.715 NS 0.1741 NS 0.1741 NS 0.461 NS NES 7.463 NS RED MARC RED RED MARC RED RED RED RED RED MARC RED RED RED MARC RED RED RED MARC RED RED RED MARC RED REL r(...)house [89] 11.121 ns 0.6774 ns 1.9106 ns 10.612 ns Marcell 红 r(...)house [89] 16.739 ns 0.4468 ns 1.3033 ns 16.853 ns

完整的测试代码

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

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


为什么不能在 string.IsNullOrEmpty 之后使用 throw 关键字(重要提示:不要在此处“抛出”!)?
可以使用 throw 关键字,但它的存在会阻止某些编译器优化,例如内联。您可以在有或没有它的情况下运行示例,您会发现它确实会影响性能。
P
Peter Mortensen

最快的方法:

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

Test results


我建议在 null 或空时返回 s 参数。
P
Peter Mortensen

由于这个问题是关于最大化性能,所以我采用 Darren's version 来使用 Span,这样可以减少垃圾并将速度提高约 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 纳秒 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);
        }
    }

}

您可能应该防范超长字符串。如果您有超过约 1MB 的字符,stackalloc 将破坏堆栈。
请使用 string.Create() 查看我的 improved answer
J
JoelFan

尝试这个:

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

或者可能是其他一些字符类(即字母数字 \w),以便该函数可识别 unicode
@DmitryLedentsov- C# 字符串类基于 UTF-16 字符构建。 String Class “将文本表示为 UTF-16 代码单元序列。”
一个解释将是有序的。例如,要点/想法是什么?请通过 editing your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似内容 - 答案应该看起来好像是今天写的)。
最好和最小的答案!
P
Peter Mortensen

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

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

感谢您提供的小解决方案,而不是仅针对字符串单词的几行代码!
P
Peter Mortensen

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

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

这可以通过一个简单的 char[] 来完成,而不是让 StringBuilder 的所有基础结构包装它。使用 str.ToCharArray() 代替 new StringBuilder(str),使用 new string(charArray) 代替 sb.ToString()StringBuilder 模拟字符数组本机公开的索引类型,因此实际的 .ToUpper 行可以基本相同。 :-)
Darren(一年后)展示了如何使用 ToCharArray 执行此操作,正如 @JonathanGilbert 所建议的那样
C
CAOakley

由于我碰巧也在做这件事,并且正在四处寻找任何想法,这就是我找到的解决方案。它使用 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);
}

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


P
Peter Mortensen

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

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

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


P
Peter Mortensen

这是一种将其作为扩展方法的方法:

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

然后可以这样调用它:

//yields "This is Brian's test.":
"this is Brian's test.".UpperCaseFirstCharacter();

这里有一些单元测试:

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

string.Format 太过分了;只需执行 text.Substring(0, 1).ToUpper() + text.Substring(1)
P
Peter Mortensen

我在 C# Uppercase First Letter - 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);
}

这与 4 年前 Equiso 的回答相比有何改进?
P
Peter Mortensen

这会做到这一点,尽管它也会确保没有错误的大写字母不在单词的开头。

public string(string s)
{
    System.Globalization.CultureInfo c = new System.Globalization.CultureInfo("en-us", false)
    System.Globalization.TextInfo t = c.TextInfo;

    return t.ToTitleCase(s);
}

在调用 ToTitleCase 之前需要对 s 进行空检查。
@CarlosMuñoz tlhIngan Hol 在其脚本中没有字母大小写。 :-)
S
Shailesh
string emp="TENDULKAR";
string output;
output=emp.First().ToString().ToUpper() + String.Join("", emp.Skip(1)).ToLower();

为什么 ToLower() 在尾部?除第一个字母外,其他字母没有要求。
String 可以是任何它的 UpperLower。所以它是所有字符串的通用解决方案。
为什么是 Join 而不是 emp.First().ToString().ToUpper() + emp.Substring(1);?可能也需要更具防御性:output = string.IsNullOrEmpty(emp) ? string.Empty : [...]。另外,首先,同意@CarlosMuñoz - 您不需要 ToLower() 来回答 OP 的问题。
@ruffin-->使用 Substring 也是一种很好的代码编写风格,我同意您修剪代码的解决方案,但在这种情况下编写 ToLower() 是一种很好的编程习惯。string 可以是任何东西 在 Upper 情况下或 Lower 情况下取决于用户输入,我给出了一个通用的解决方案。
@Shailesh - 但是,问题并没有要求只有第一个字母是大写字母。它要求将第一个字母改为大写。在没有作者进一步澄清的情况下,最自然的假设是字符串的其余部分保持不变。鉴于您在三年后回答,请假设接受的答案符合提问者的要求。如果有一些技术原因需要不同的做法,请只给出不同的答案。
P
Peter Mortensen

我们可以这样做(C# 8.0、.NET 5):

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

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

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

否则,代码将获取第一个字符 input[0] 并使用 char.ToUpperInvariant 将其转换为大写。并连接其余的 input[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

我使用 Jon Skeet 的 Simple microbenchmarking in C# 中的代码在 Windows 10、Intel Core i3 上运行它。


P
Peter Mortensen

当您只需要以下内容时,这里似乎有很多复杂性:

/// <summary>
/// Returns the input string with the first character converted to uppercase if a letter
/// </summary>
/// <remarks>Null input returns null</remarks>
public static string FirstLetterToUpperCase(this string s)
{
    if (string.IsNullOrWhiteSpace(s))
        return s;

    return char.ToUpper(s[0]) + s.Substring(1);
}

值得注意的点:

这是一种扩展方法。如果输入为空、空或空格,则输入按原样返回。 String.IsNullOrWhiteSpace 是在 .NET Framework 4 中引入的。这不适用于旧框架。


我看不出这对四年前接受的原始答案有何改进。事实上,它是不一致的(无害,但四年后,我对新答案增加了好处有很高的标准):使用较新的 IsNullOrWhiteSpace 而不是 IsNullOrEmpty 的唯一好处,是如果您要查找并更改第一个非空白。但你没有 - 你总是在 s[0] 上操作。因此,使用 IsNullOrWhiteSpace 毫无意义[在语义和性能上]。
...为什么 IsNullOrWhiteSpace 的这种用法让我感到困扰,是粗心的读者可能会认为“他检查了空格,所以下面的代码确实找到并更改了一个字母,即使它前面有空格”。由于您的代码无法更改以空格开头的“首字母”,因此使用 IsNullOrWhiteSpace 只会误导读者。
...哎呀,我的意思不是接受的答案,我的意思是同一时期的Equiso's answer
P
Peter Mortensen

我认为下面的方法是最好的解决方案。

class Program
{
    static string UppercaseWords(string value)
    {
        char[] array = value.ToCharArray();
        // Handle the first letter in the string.
        if (array.Length >= 1)
        {
            if (char.IsLower(array[0]))
            {
                array[0] = char.ToUpper(array[0]);
            }
        }
        // Scan through the letters, checking for spaces.
        // ... Uppercase the lowercase letters following spaces.
        for (int i = 1; i < array.Length; i++)
        {
            if (array[i - 1] == ' ')
            {
                if (char.IsLower(array[i]))
                {
                    array[i] = char.ToUpper(array[i]);
                }
            }
        }
        return new string(array);
    }

    static void Main()
    {
        // Uppercase words in these strings.
        const string value1 = "something in the way";
        const string value2 = "dot net PERLS";
        const string value3 = "String_two;three";
        const string value4 = " sam";
        // ... Compute the uppercase strings.
        Console.WriteLine(UppercaseWords(value1));
        Console.WriteLine(UppercaseWords(value2));
        Console.WriteLine(UppercaseWords(value3));
        Console.WriteLine(UppercaseWords(value4));
    }
}

Output

Something In The Way
Dot Net PERLS
String_two;three
 Sam

Reference


P
Peter Mortensen

解决您的问题的可能解决方案:

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

P
Patrick Knott

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

IsNullOrWhiteSpace 说明只是空格或空/空的字符串。 .Trim() 删除字符串前后的空白。 .First() 采用 IEnumerable (或字符串)的第一个元素。我们应该检查它是否是一个可以/应该是大写的字母。然后我们添加字符串的其余部分,只要长度表明我们应该这样做。根据 .NET 最佳实践,我们应该在 System.Globalization.CultureInfo 下提供文化。将它们作为可选参数提供使此方法完全可重用,而无需每次都键入所选的文化。我还注意到我的答案和大多数答案都没有在字符串的开头保留空格。这还将展示如何维护该空白。 //使用正则表达式将第一个字母大写忽略所有字符。公共静态字符串 RegCapString(此字符串 instring,字符串culture = "en-US",bool useSystem = false) { if (string.IsNullOrWhiteSpace(instring)) { return instring; } var m = Regex.Match(instring, "[A-Za-z]").Index;返回 instring.Substring(0, m) + instring[m].ToString().ToUpper(new CultureInfo(culture, useSystem)) + instring.Substring(m + 1); } //如果是字母则大写第一个字符忽略空格。公共静态字符串 CapString(此字符串 instring,字符串文化 =“en-US”,bool useSystem = false){ if (string.IsNullOrWhiteSpace(instring) || !char.IsLetter(instring.Trim().First())) {返回字符串; } 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) : ""); }


虽然这涵盖了大多数情况,但考虑到每个操作创建的字符串数量,它会不会很慢?这里有大量的字符串分配。最好将它分配一次,并且只分配一次。
“可枚举”似乎不正确。是不是写法不一样?
抱歉,@PeterMortensen 是的,大写时它是正确的,它看起来是正确的。
@DouglasGaskell 我更改了答案以包含正则表达式以获得非常简单的答案。我还压缩了我原来的方法,减少了每个评论的字符串分配数量。您可以在编辑历史记录中看到我的原始答案。
Z
Zamir

扩展上述 Carlos 的问题,如果您想将多个句子大写,可以使用以下代码:

    /// <summary>
    /// Capitalize first letter of every sentence. 
    /// </summary>
    /// <param name="inputSting"></param>
    /// <returns></returns>
    public string CapitalizeSentences (string inputSting)
    {
        string result = string.Empty;
        if (!string.IsNullOrEmpty(inputSting))
        {
            string[] sentences = inputSting.Split('.');

            foreach (string sentence in sentences)
            {
                result += string.Format ("{0}{1}.", sentence.First().ToString().ToUpper(), sentence.Substring(1)); 
            }
        }

        return result; 
    }

“卡洛斯”指的是什么? OP(原始海报)?
P
Peter Mortensen

这是对我有用的代码:

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

P
Peter Mortensen

似乎这里给出的解决方案都不会处理字符串之前的空格。

只是将其添加为一个想法:

public static string SetFirstCharUpper2(string aValue, bool aIgonreLeadingSpaces = true)
{
    if (string.IsNullOrWhiteSpace(aValue))
        return aValue;

    string trimmed = aIgonreLeadingSpaces
           ? aValue.TrimStart()
           : aValue;

    return char.ToUpper(trimmed[0]) + trimmed.Substring(1);
}

它应该处理 this won't work on other answers(该句子开头有一个空格),如果您不喜欢空格修剪,只需传递一个 false 作为第二个参数(或将默认值更改为 false,然后通过true 如果你想处理空间))。


P
Peter Mortensen

FluentSharp 具有执行此操作的 lowerCaseFirstLetter 方法。


P
Peter Mortensen

这是最快的方法:

public static unsafe void ToUpperFirst(this string str)
{
    if (str == null)
        return;
    fixed (char* ptr = str)
        *ptr = char.ToUpper(*ptr);
}

在不更改原始字符串的情况下:

public static unsafe string ToUpperFirst(this string str)
{
    if (str == null)
        return null;
    string ret = string.Copy(str);
    fixed (char* ptr = ret)
        *ptr = char.ToUpper(*ptr);
    return ret;
}

欢迎来到堆栈溢出!虽然这段代码可以回答这个问题,但最好包含一些上下文并解释它是如何工作的。最后一行有很多事情要做,那么为什么这会导致最高性能呢?
@Anonymous 请在您的帖子中edit,而不是仅仅发表评论。
为了扩展 Grax 的评论,这是因为 C# 实习生字符串的方式。所以引用真的可能是相等的。
不仅仅是实习。字符串应该是不可变的,并且所有 .NET 代码都假定它是不可变的。两个变量指向同一个底层 System.String 对象的 任何 情况都会看到字符串从其下方发生变化。考虑是否将给定的 System.String 对象用作 Dictionary<string, TValue> 中的键 - 字符串的散列可能突然不正确,将值放入错误的存储桶并破坏数据结构。第二个版本是唯一可以使用的“安全”版本,甚至在技术上它也违反了运行时的假设和 CLR 规范。
不要使用这两种方法中的任何一种。方法 1:违反内置 string 类的不变性是不可接受的 - 违反了健全的编码原则。如果程序员想要一个可变字符串,他们应该围绕 char[] 构建一个自定义类。方法 #2:无需进行 unsafe 编程即可完成此操作。请参阅使用 ToCharArrayDarren's answer
P
Peter Mortensen

以下功能适用于所有方式:

static string UppercaseWords(string value)
{
    char[] array = value.ToCharArray();
    // Handle the first letter in the string.
    if (array.Length >= 1)
    {
        if (char.IsLower(array[0]))
        {
            array[0] = char.ToUpper(array[0]);
        }
    }
    // Scan through the letters, checking for spaces.
    // ... Uppercase the lowercase letters following spaces.
    for (int i = 1; i < array.Length; i++)
    {
        if (array[i - 1] == ' ')
        {
            if (char.IsLower(array[i]))
            {
                array[i] = char.ToUpper(array[i]);
            }
        }
    }
    return new string(array);
}

我发现了here


为什么?当已经有这么多看起来相似的答案时,为什么还要添加另一个答案?所有现有答案有什么问题,促使您添加另一个答案?
因为这个答案在所有方面都是正确的。别紧张。
对不起;我是不必要的苛刻。我会坚持事实:1)这与七年前的thattolleyguy's answer基本相同。 2)这与该答案具有相同的缺陷:不处理空白字符以外的空白。 3)这回答了一个与 OP 所问的问题略有不同的问题。如果您希望 所有 个单词的首字母大写,请使用这样的答案。 4) 通常,更简单的方法是使用 TitleInfo.ToTitleCase。 (另一方面,代码示例的一个优点是可以根据需要进行自定义。)
更正自己:这与 thattolleyguy 的方法不同:它留下的字母不是单词的第一个字母。相反,它是 zamoldar's answer重复。有利的是,感谢 Darian 提供了指向源的链接 - zamoldar 似乎抄袭了没有给予信任。 由于提供了该源链接,从而改进了讨论,我赞成这个答案,尽管我对此提出了批评。
Darian,可以进行两项改进:1) 使用 char.IsWhiteSpace( array[ i -1 ] ) 而不是 .. == ' ' 来处理所有空白。 2)删除做 if (char.isLower(..)) 的两个地方 - 它们没有任何作用。 ToUpper 如果字符不是小写,则什么也不做。