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
если вы знаете, что формат не изменяет данные, а просто объединение желательно.