最佳实践 - 将字符串的第一个字符转换为小写

154
我希望有一个方法可以将字符串的第一个字符转换为小写。
我的方法如下:
1.
public static string ReplaceFirstCharacterToLowerVariant(string name)
{
    return String.Format("{0}{1}", name.First().ToString().ToLowerInvariant(), name.Substring(1));
}

2.
public static IEnumerable<char> FirstLetterToLowerCase(string value)
{
    var firstChar = (byte)value.First();
    return string.Format("{0}{1}", (char)(firstChar + 32), value.Substring(1));
}

什么是您的方法?
13个回答

259

我会使用简单的字符串连接:

Char.ToLowerInvariant(name[0]) + name.Substring(1)

第一种解决方案并不是最优化的,因为 string.Format 很慢,并且如果您有一个永远不会改变的格式,则不需要它。此外,它还会生成一个多余的字符串来将字母转换为小写,这是不必要的。

使用 "+ 32" 的方法很丑陋/不可维护,因为它需要了解ASCII字符值偏移量。它还将在Unicode数据和ASCII符号字符中生成错误的输出。


4
我会这样做:char.ToLower(name[0]).ToString() + name.Substring(1) - Andrey
8
@Rookian说:当你要拼接很多字符串时,“+”运算符速度很慢。在这种情况下,使用“StringBuilder”会更加高效。但是,“+”比“string.Format”快得多。只有在需要格式化内容(例如显示整数、双精度数或日期)时才使用后者。 - Dirk Vollmar
6
只有在迭代地连接大量字符串时,才会变得很慢。如果你通过单次操作将它们全部连接起来,+ 运算符就不会很慢,因为编译器会将其转换为 String.Concat(但是由于某些愚蠢的原因,String.JoinString.Concat 更快)。 - Thorarin
3
我使用了扩展方法。public static string ToLowerFirst(this string source) { if (string.IsNullOrWhiteSpace(source)) return source; var charArray = source.ToCharArray(); charArray[0] = char.ToLower(charArray[0]); return new string(charArray); }基于@MatteoMigliore的评论。 - KregHEk
2
除非您正在循环中连接字符串,否则担心+、stringbuilder、string.format或string.concat之间的区别是过早优化。 - stannius
显示剩余3条评论

72

根据情况,进行一些防御性编程可能是可取的:

public static string FirstCharacterToLower(string str)
{
    if (String.IsNullOrEmpty(str) || Char.IsLower(str, 0))
        return str;

    return Char.ToLowerInvariant(str[0]) + str.Substring(1);
}
if语句也可以防止在不需要更改的情况下构建新字符串。你可能希望在输入为null时让方法失败并抛出ArgumentNullException
正如其他人提到的,对于这种情况使用String.Format是过度设计了。

请纠正我,但是str.Substring(1)将返回位置1处的符号,因为该方法的计数未指示。 因此,您将在小写字母的char [0]中加上位置1的char。 所以我更喜欢从字符串的第一个字符开始删除一个字符。结果是没有第一个字母的字符串。然后我会将此字符串添加到转换为小写字母的第一个字符。 - fedotoves
4
考虑你已经被纠正:http://msdn.microsoft.com/zh-cn/library/hxthx5h6%28VS.90%29.aspx - Thorarin

9

如果有人偶然遇到这个答案,我希望它能对你有所帮助。

我认为最好的方法是将其作为扩展方法,然后可以使用yourString.FirstCharacterToLower()进行调用。

public static class StringExtensions
{
    public static string FirstCharacterToLower(this string str)
    {
        if (String.IsNullOrEmpty(str) || Char.IsLower(str, 0))
        {
            return str;
        }

        return Char.ToLowerInvariant(str[0]) + str.Substring(1);
    }
}

5
我所知道的最快解决方案而不滥用C#:
public static string LowerCaseFirstLetter(string value)
{
    if (value?.Length > 0)
    {
        var letters = value.ToCharArray();
        letters[0] = char.ToLowerInvariant(letters[0]);
        return new string(letters);
    }
    return value;
}

4

使用 C# 8.0 或更高版本的范围操作符,您可以这样做:

Char.ToLowerInvariant(name[0]) + name[1..];

3

Mine is

if (!string.IsNullOrEmpty (val) && val.Length > 0)
{
    return val[0].ToString().ToLowerInvariant() + val.Remove (0,1);   
}

4
我很好奇,为什么要使用 val.Remove?这对我来说有点违反直觉。 - Thorarin
@Thorarin 显然是因为您想要删除第一个字符(因为您要在前面添加小写版本)。 - Riki

2
如果您关心性能,我会选择
  public static string FirstCharToLower(this string str)
    => string.Create(str.Length, str, (output, input) =>
      {
        input.CopyTo(output);
        output[0] = char.ToLowerInvariant(input[0]);
      });

我进行了一些快速基准测试,似乎比此处发布的最快解决方案至少快两倍,并且比多个输入长度中最差的解决方案快3.5倍。
没有输入检查,这应该是调用者的责任。如果需要的话,可以在热路径中避免分支,让您提前准备数据并进行快速批量处理,而不会被拖慢速度。

2

我喜欢被接受的答案,但除了检查 string.IsNullOrEmpty 外,如果你在处理缩写词,我也会检查 Char.IsLower(name[1])。例如,你不想让 "AIDS" 变成 "aIDS"。


9
在我看来,这是呼叫者的责任。 - onof

0

将几个函数组合成可链式调用的扩展。添加了对空格和非字母的短路处理。

public static string FirstLower(this string input) => 
    (!string.IsNullOrWhiteSpace(input) && input.Length > 0 
        && char.IsLetter(input[0]) && !char.IsLower(input[0]))
    ? input[0].ToString().ToLowerInvariant() + input.Remove(0, 1) : input;

0
使用这个:
string newName= name[0].ToString().ToLower() + name.Substring(1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接