BestPractice - преобразовать первый символ строки в нижний регистр

Я хотел бы иметь метод, который преобразует первый символ строки в нижний регистр.

My approaches:

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 ответов

Решение

Я бы использовал простую конкатенацию:

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

Первое решение не оптимизировано, потому что string.Format медленный и вам не нужен, если у вас есть формат, который никогда не изменится. Он также генерирует дополнительную строку для преобразования буквы в нижний регистр, которая не нужна.

Подход с "+ 32" является уродливым / не обслуживаемым, поскольку требует знания смещений значений символов ASCII. Это также сгенерирует неправильный вывод с данными Unicode и символьными символами ASCII.

В зависимости от ситуации может потребоваться небольшое защитное программирование:

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 Кроме того, оператор предотвращает создание новой строки, если она все равно не будет изменена. Возможно, вы захотите, чтобы метод потерпел неудачу при нулевом вводе, и бросить ArgumentNullException,

Как уже упоминали люди, используя String.Format это излишне.

На всякий случай это поможет любому, кто случайно наткнется на этот ответ.

Я думаю, что это будет лучше всего в качестве метода расширения, тогда вы можете вызвать его с помощью 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);
    }
}

Самое быстрое решение, которое я знаю, не злоупотребляя 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;
}

С оператором диапазона С# 8.0 или выше вы можете сделать это:

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

Если вам важна производительность, я бы пошел с

        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 раза быстрее, чем худшее, при разной длине ввода.

Проверка ввода не выполняется, так как это должна быть ответственность вызывающего абонента. Это позволяет вам заранее подготовить данные и выполнить быструю массовую обработку, не замедляющуюся из-за наличия веток на вашем горячем пути, если они вам когда-либо понадобятся.

Мой

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

Мне нравится принятый ответ, но помимо проверки string.IsNullOrEmpty Я также проверил бы, если Char.IsLower(name[1]) в случае, если вы имеете дело с сокращением. Например, вы не хотели бы, чтобы "СПИД" стал "СПИДом".

Использовать этот:

string newName= name[0].ToString().ToLower() + name.Substring(1)

Объединили несколько и сделали его цепным расширением. Добавлено короткое замыкание на пробел и не букву.

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;

Это небольшой метод расширения, использующий последний синтаксис и правильные проверки

public static class StringExtensions
{
    public static string FirstCharToLower(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().ToLower() + input.Substring(1);
        }
    }
}

Если вы не хотите дважды ссылаться на свою строку в своем выражении, вы можете сделать это, используя System.Linq.

new string("Hello World".Select((c, i) => i == 0 ? char.ToLower(c) : c).ToArray())

Таким образом, если ваша строка получена из функции, вам не нужно сохранять результат этой функции.

new string(Console.ReadLine().Select((c, i) => i == 0 ? char.ToLower(c) : c).ToArray())

Лучше использовать String.Concat чем String.Format если вы знаете, что формат не изменяет данные, а просто объединение желательно.

Другие вопросы по тегам