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

我有一个DetailsViewTextBox 我想要输入数据保存永远大写第一个字母.

例子:

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

我怎样才能实现这个最大限度地提高性能?


# EYZ0:

根据答案和答案下的评论,许多人认为这是在询问字符串中所有个单词的大写。例如,=> Red House 不是,但如果这是你想要的,寻找一个使用TextInfoToTitleCase方法的答案。(注:实际问题的答案是不正确的。) 注意事项请参阅TextInfo。ToTitleCase文档(不涉及全大写单词-它们被认为是首字母缩写;“不应该”的单词中间可能会出现小写字母;被降低,例如,"McDonald"→“Mcdonald";不保证处理所有特定于区域性的细微差别重大写规则。)


# EYZ0:

问题是模棱两可的,第一个字母之后的字母是否应该是强迫小写。公认的答案假设只有第一个字母需要修改。如果您想强制将字符串中除第一个字母外的所有字母改为小写,请查找包含ToLower不包含ToTitleCase的答案。

683034 次浏览
string s_Val = "test";
if (s_Val != "")
{
s_Val  = char.ToUpper(s_Val[0]);
if (s_Val.Length > 1)
{
s_Val += s_Val.Substring(1);
}
}

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

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);
}
string input = "red HOUSE";
System.Text.StringBuilder sb = new System.Text.StringBuilder(input);


for (int j = 0; j < sb.Length; j++)
{
if ( j == 0 ) //catches just the first letter
sb[j] = System.Char.ToUpper(sb[j]);
else  //everything else is lower case
sb[j] = System.Char.ToLower(sb[j]);
}
// Store the new string.
string corrected = sb.ToString();
System.Console.WriteLine(corrected);
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();
}
< p >老回答: 这使得每个首字母都是大写

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

这就可以了,尽管它也会确保没有错误的大写字母不是在单词的开头。

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

第一个字母和空格后面的每个字母都大写,其他字母都小写。

public string CapitalizeFirstLetterAfterSpace(string input)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder(input);
bool capitalizeNextLetter = true;
for(int pos = 0; pos < sb.Length; pos++)
{
if(capitalizeNextLetter)
{
sb[pos]=System.Char.ToUpper(sb[pos]);
capitalizeNextLetter = false;
}
else
{
sb[pos]=System.Char.ToLower(sb[pos]);
}


if(sb[pos]=' ')
{
capitalizeNextLetter=true;
}
}
}

不同c#版本的解决方案

c# 8,至少。net Core 3.0或。net Standard 2.1

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

这个版本比较短。要获得更快的解决方案,请查看迭戈的回答

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

可能最快的解决方案是达伦的(甚至有一个基准测试),尽管我将更改它的string.IsNullOrEmpty(s)验证抛出异常,因为最初的需求期望第一个字母存在,以便它可以大写。注意,这段代码适用于泛型字符串,而不是Textbox中的有效值。

这里有一个方法来做它作为一个扩展方法:

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

试试这个:

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

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

如果性能/内存使用是一个问题,那么它只创建一个(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;
}

您可以使用“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
}
}
string emp="TENDULKAR";
string output;
output=emp.First().ToString().ToUpper() + String.Join("", emp.Skip(1)).ToLower();

使用以下代码:

string strtest ="PRASHANT";
strtest.First().ToString().ToUpper() + strtest.Remove(0, 1).ToLower();

最简单和最快的方法是将字符串的第一个字符替换为大写字符:

string str = "test";<br>
str = str.Replace(str[0], char.ToUpper(str[0]));

用这种方法,你可以把每个单词的第一个字符抬高。

< h3 id = " example-k4y4 " > < / h3 >例子

“你好wOrld"=比;“你好World"

public static string FirstCharToUpper(string input)
{
if (String.IsNullOrEmpty(input))
throw new ArgumentException("Error");
return string.Join(" ", input.Split(' ').Select(d => d.First().ToString().ToUpper() +  d.ToLower().Substring(1)));
}

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

我相信有一种方法可以优化或者清理一下。

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


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

我在 c#大写首字母-点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);
}

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

只是加上这个想法:

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))。

当你所需要的只是:

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

值得注意的点:

  1. 这是一个扩展方法。

  2. 如果输入是空的,空的或空白的,输入将按原样返回。

  3. 字符串。IsNullOrWhiteSpace是. net Framework 4引入的。这将不适用于旧的框架。

我从 c#大写首字母-点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接受的答案的初始测试:

    /// <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);
}
 private string capitalizeFirstCharacter(string format)
{
if (string.IsNullOrEmpty(format))
return string.Empty;
else
return char.ToUpper(format[0]) + format.ToLower().Substring(1);
}

FluentSharp有lowerCaseFirstLetter方法可以做到这一点。

这是最快的方法:

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

如果你只关心第一个字母是否大写,而不关心字符串的其他部分,你可以只选择第一个字符,使其大写,并将其与没有原始第一个字符的字符串的其余部分连接起来。

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

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

利用第一个字母最简单的方法是:

  1. 使用System.Globalization < p >;

     // Creates a TextInfo based on the "en-US" culture.
    TextInfo myTI = new CultureInfo("en-US", false).
    
    
    myTI.ToTitleCase(textboxname.Text)
    

最快的方法:

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

测试结果 . b

正确的方法是使用文化:

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

这将大写字符串中的每个单词,例如:“红房子”——>“红房子”。该解决方案还将减少单词中的大写字母,例如:"old McDonald"——> "old McDonald"。

下面的函数对所有方式都是正确的:

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

我发现在这里

我用这个来纠正名字。它的基本原理是,如果字符遵循特定的模式,则将其更改为大写。在这种情况下,我选择了空格和“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();
}

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

我想提供一个“最大performance"的答案。在我看来,“最大performance"答案捕获了所有场景,并为解释这些场景的问题提供了答案。所以,这是我的答案。原因如下:

  1. IsNullOrWhiteSpace用于仅为空格或null/空的字符串。

  2. . trim()删除字符串前后的空白。

  3. .First()取IEnumerable<TSource>(或字符串)。

  4. 我们应该检查一下它是否是一个可以/应该大写的字母。

  5. 然后添加字符串的其余部分,仅当长度指示我们应该这样做时。

  6. 通过. net最佳实践,我们应该在System.Globalization.CultureInfo下提供一个区域性。

  7. 提供它们作为可选参数使此方法完全可重用,而不必每次都键入所选区域性。

  8. 我还注意到我的答案和大多数这些答案都没有保持字符串开头的空白。这还将显示如何维护空白。

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

最近我有一个类似的需求,并记得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));
}
}

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

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

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

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

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

参考

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

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

解决问题的可能方法:

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

由于这个问题是关于最大限度地提高性能的,所以我采用达伦的版本来使用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);
}
< h2 id = " performance-irb7 " > < / h2 >性能
< span style=" font - family:宋体;">是< / th > < span style=" font - family:宋体;"> < / th >错误 < span style=" font - family:宋体;"> StdDev < / th > . . . . . . . . . . .
方法 数据
卡洛斯 红色的 107.29 ns 2.2401 ns3.9234 ns
达伦 红色的 0.8632 ns
Marcell 红色的 0.3902 ns0.3459 ns
卡洛斯 红房子 106.78 ns1.9713 ns 1.8439 ns
达伦 红房子 0.4253 ns0.3978 ns
Marcell 红房子 0.3888 ns0.3637 ns
< / div > # EYZ0
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);
}
}


}

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

性能

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

< span style=" font - family:宋体;">是< / th > < span style=" font - family:宋体;"> < / th >错误 < span style=" font - family:宋体;"> StdDev < / th > < span style=" font - family:宋体;"> < / th >中值 . . . . . . . . . . . . . . . .
方法 数据
精英语言 红色的 8.545 ns0.4612 ns8.075 ns
Marcell 红色的 9.153 ns0.3377 ns0.9471 ns8.946 ns
精英语言 红房子 7.715 ns 0.1741 ns0.4618 ns10.537 ns0.5002 ns10.377 ns
精英语言 红房子[89] 0.6774 ns10.612 ns
Marcell 红房子[89] 16.739 ns0.4468 ns1.3033 ns 16.853 ns
< / div > # EYZ0
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]);
});
}
}
}

如果你能让它更快,请告诉我!

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

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

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


如果input是一个空字符串,我们得到一个空字符串。如果input = null,则得到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

我在Windows 10上运行它,Intel Core i3,使用代码从简单的c#微基准测试 by Jon Skeet。

下面是对我有用的代码:

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

这也可以使用Take, Skip和Aggregate:

    public static string FirstCharToUpper(this string text)
{
if (String.IsNullOrEmpty(text)) return String.Empty;
var first = text.Take(1).ToArray()[0].ToString().ToUpper();
var rest = text.Skip(1).Aggregate("", ((xs, x) => xs + x));
return first + rest;
}