Как лучше всего преобразовать регистр Паскаля (верхний регистр верблюда) в предложение.
Например, начиная с
"AwaitingFeedback"
и преобразовав это в
"Awaiting feedback"
C# предпочтительнее, но я мог бы преобразовать его из Java или подобного.
@kgiannakakis соответственно изменил вопрос. Я всегда забываю, как идут имена, особенно с верхним и нижним регистром Camel.





Псевдокод:
NewString = "";
Loop through every char of the string (skip the first one)
If char is upper-case ('A'-'Z')
NewString = NewString + ' ' + lowercase(char)
Else
NewString = NewString + char
Лучшие способы, возможно, могут быть выполнены с использованием регулярных выражений или подпрограмм замены строк (замените 'X' на 'x')
Я бы использовал регулярное выражение, вставляя пробел перед каждым символом верхнего регистра, а затем опуская всю строку.
string spacedString = System.Text.RegularExpressions.Regex.Replace(yourString, "\B([A-Z])", " \k");
spacedString = spacedString.ToLower();
Я не знаю C#, но не думаю, что в разделе замены разрешены экранирования типа \ s: как язык узнает, нужно ли вставлять пробел, табуляцию или что-то еще? :-)
Вы правы, должно быть проще заменить на четкое "".
Единственное, что я бы сказал, это вызовет "ожидание обратной связи"
Ну, вам обязательно нужно удалить первый пробел и поставить первый символ выше. Возможно, добавьте перед шаблоном "\ B", чтобы не совпадать с первым символом.
Ну вот...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CamelCaseToString
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(CamelCaseToString("ThisIsYourMasterCallingYou"));
}
private static string CamelCaseToString(string str)
{
if (str == null || str.Length == 0)
return null;
StringBuilder retVal = new StringBuilder(32);
retVal.Append(char.ToUpper(str[0]));
for (int i = 1; i < str.Length; i++ )
{
if (char.IsLower(str[i]))
{
retVal.Append(str[i]);
}
else
{
retVal.Append(" ");
retVal.Append(char.ToLower(str[i]));
}
}
return retVal.ToString();
}
}
}
Вы должны ToUpper () первым символом, иначе ваша процедура не будет работать с истинным camelCase, только с PascalCase
Да, приятный улов, я знал, что что-то не так (но не мог понять это), когда он сказал, что "AwaitingFeedback" - это верблюжий случай!
Это легко сделать в JavaScript (или PHP и т. д.), Где вы можете определить функцию в вызове замены:
var camel = "AwaitingFeedbackDearMaster";
var sentence = camel.replace(/([A-Z].)/g, function (c) { return ' ' + c.toLowerCase(); });
alert(sentence);
Хотя я не решил проблему с начальной шапкой ... :-)
Теперь для решения Java:
String ToSentence(String camel)
{
if (camel == null) return ""; // Or null...
String[] words = camel.split("(?=[A-Z])");
if (words == null) return "";
if (words.length == 1) return words[0];
StringBuilder sentence = new StringBuilder(camel.length());
if (words[0].length() > 0) // Just in case of camelCase instead of CamelCase
{
sentence.append(words[0] + " " + words[1].toLowerCase());
}
else
{
sentence.append(words[1]);
}
for (int i = 2; i < words.length; i++)
{
sentence.append(" " + words[i].toLowerCase());
}
return sentence.toString();
}
System.out.println(ToSentence("AwaitingAFeedbackDearMaster"));
System.out.println(ToSentence(null));
System.out.println(ToSentence(""));
System.out.println(ToSentence("A"));
System.out.println(ToSentence("Aaagh!"));
System.out.println(ToSentence("stackoverflow"));
System.out.println(ToSentence("disableGPS"));
System.out.println(ToSentence("Ahh89Boo"));
System.out.println(ToSentence("ABC"));
Обратите внимание на трюк, позволяющий разделить предложение без потери символа ...
Вот основной способ сделать это, что я придумал, используя Regex
public static string CamelCaseToSentence(this string value)
{
var sb = new StringBuilder();
var firstWord = true;
foreach (var match in Regex.Matches(value, "([A-Z][a-z]+)|[0-9]+"))
{
if (firstWord)
{
sb.Append(match.ToString());
firstWord = false;
}
else
{
sb.Append(" ");
sb.Append(match.ToString().ToLower());
}
}
return sb.ToString();
}
Он также разделит числа, которые я не указал, но которые будут полезны.
string camel = "MyCamelCaseString";
string s = Regex.Replace(camel, "([A-Z])", " $1").ToLower().Trim();
Console.WriteLine(s.Substring(0,1).ToUpper() + s.Substring(1));
Обновлено: не заметил ваших требований к корпусу, изменен соответствующим образом. Вы можете использовать средство сопоставления для определения регистра, но я думаю, что подстрока проще. Вы также можете обернуть его второй заменой регулярного выражения, где вы меняете первый символ
"^\w"
к верхнему
\U (i think)
Преимущественно уже ответил здесь
Небольшое изменение в принятом ответе, чтобы преобразовать вторую и последующие буквы с заглавной буквы в нижний регистр, поэтому измените
if (char.IsUpper(text[i]))
newText.Append(' ');
newText.Append(text[i]);
к
if (char.IsUpper(text[i]))
{
newText.Append(' ');
newText.Append(char.ToLower(text[i]));
}
else
newText.Append(text[i]);
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}
В версиях Visual Studio после 2015 года можно делать
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => $"{m.Value[0]} {char.ToLower(m.Value[1])}");
}
По материалам: Преобразование регистра Паскаля в предложения с использованием регулярного выражения
Решение xquery, которое работает как для UpperCamel, так и для lowerCamel case:
Чтобы вывести регистр предложения (заглавными являются только первые символы первого слова):
declare function content:sentenceCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),lower-case(replace($remainingCharacters, '([A-Z])', ' $1')))
};
Чтобы вывести регистр заголовка (первый символ каждого слова должен быть заглавным):
declare function content:titleCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),replace($remainingCharacters, '([A-Z])', ' $1'))
};
Это работает для меня:
Regex.Replace(strIn, "([A-Z]{1,2}|[0-9]+)", " $1").TrimStart()
Как это изменит регистр буквы после пробела?
Это может не вернуть то, что вы намереваетесь использовать для таких случаев, как AwaitingTFeedback или Awaiting9Feedback. Для меня лучше Джеф ответ (который возвращает Awaiting T Feedback и Awaiting9 Feedback соответственно).
Это похоже на @SSTA, но более эффективно, чем вызов TrimStart.
Regex.Replace("ThisIsMyCapsDelimitedString", "(\\B[A-Z])", " $1")
Обнаружил это в источнике MvcContrib, но, похоже, здесь еще не упоминается.
return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
Я обнаружил, что делаю нечто подобное, и я благодарен за отправную точку этого обсуждения. Это мое решение, помещенное как метод расширения к строковому классу в контексте консольного приложения.
using System;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string piratese = "avastTharMatey";
string ivyese = "CheerioPipPip";
Console.WriteLine("{0}\n{1}\n", piratese.CamelCaseToString(), ivyese.CamelCaseToString());
Console.WriteLine("For Pete\'s sake, man, hit ENTER!");
string strExit = Console.ReadLine();
}
}
public static class StringExtension
{
public static string CamelCaseToString(this string str)
{
StringBuilder retVal = new StringBuilder(32);
if (!string.IsNullOrEmpty(str))
{
string strTrimmed = str.Trim();
if (!string.IsNullOrEmpty(strTrimmed))
{
retVal.Append(char.ToUpper(strTrimmed[0]));
if (strTrimmed.Length > 1)
{
for (int i = 1; i < strTrimmed.Length; i++)
{
if (char.IsUpper(strTrimmed[i])) retVal.Append(" ");
retVal.Append(char.ToLower(strTrimmed[i]));
}
}
}
}
return retVal.ToString();
}
}
}
Я предпочитаю использовать для этого Гуманизатор. Humanizer - это переносимая библиотека классов, которая отвечает всем вашим потребностям .NET для управления и отображения строк, перечислений, дат, времени, временных интервалов, чисел и количеств.
Короткий ответ
"AwaitingFeedback".Humanize() => Awaiting feedback
Длинный и описательный ответ
Humanizer может выполнять гораздо больше работы, другие примеры:
"PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence"
"Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence"
"Can_return_title_Case".Humanize(LetterCasing.Title) => "Can Return Title Case"
"CanReturnLowerCase".Humanize(LetterCasing.LowerCase) => "can return lower case"
Полный код:
using Humanizer;
using static System.Console;
namespace HumanizerConsoleApp
{
class Program
{
static void Main(string[] args)
{
WriteLine("AwaitingFeedback".Humanize());
WriteLine("PascalCaseInputStringIsTurnedIntoSentence".Humanize());
WriteLine("Underscored_input_string_is_turned_into_sentence".Humanize());
WriteLine("Can_return_title_Case".Humanize(LetterCasing.Title));
WriteLine("CanReturnLowerCase".Humanize(LetterCasing.LowerCase));
}
}
}
Выход
Awaiting feedback
Pascal case input string is turned into sentence
Underscored input string is turned into sentence Can Return Title Case
can return lower case
Если вы предпочитаете писать свой собственный код на C#, вы можете добиться этого, написав некоторые элементы кода на C#, на которые уже ответили другие.
Просто потому, что все использовали Regex (кроме этот парень), вот реализация с StringBuilder, которая в моих тестах была примерно В 5 раз быстрее. Также включает проверку чисел.
"SomeBunchOfCamelCase2".FromCamelCaseToSentence == "Some Bunch Of Camel Case 2"
public static string FromCamelCaseToSentence(this string input) {
if (string.IsNullOrEmpty(input)) return input;
var sb = new StringBuilder();
// start with the first character -- consistent camelcase and pascal case
sb.Append(char.ToUpper(input[0]));
// march through the rest of it
for(var i = 1; i < input.Length; i++) {
// any time we hit an uppercase OR number, it's a new word
if (char.IsUpper(input[i]) || char.IsDigit(input[i])) sb.Append(' ');
// add regularly
sb.Append(input[i]);
}
return sb.ToString();
}
Большинство предыдущих ответов разделяют аббревиатуры и числа, добавляя пробел перед каждым символом. Я хотел, чтобы аббревиатуры и числа оставались вместе, поэтому у меня есть простой конечный автомат, который выдает пробел каждый раз, когда ввод переходит из одного состояния в другое.
/// <summary>
/// Add a space before any capitalized letter (but not for a run of capitals or numbers)
/// </summary>
internal static string FromCamelCaseToSentence(string input)
{
if (string.IsNullOrEmpty(input)) return String.Empty;
var sb = new StringBuilder();
bool upper = true;
for (var i = 0; i < input.Length; i++)
{
bool isUpperOrDigit = char.IsUpper(input[i]) || char.IsDigit(input[i]);
// any time we transition to upper or digits, it's a new word
if (!upper && isUpperOrDigit)
{
sb.Append(' ');
}
sb.Append(input[i]);
upper = isUpperOrDigit;
}
return sb.ToString();
}
А вот несколько тестов:
[TestCase(null, ExpectedResult = "")]
[TestCase("", ExpectedResult = "")]
[TestCase("ABC", ExpectedResult = "ABC")]
[TestCase("abc", ExpectedResult = "abc")]
[TestCase("camelCase", ExpectedResult = "camel Case")]
[TestCase("PascalCase", ExpectedResult = "Pascal Case")]
[TestCase("Pascal123", ExpectedResult = "Pascal 123")]
[TestCase("CustomerID", ExpectedResult = "Customer ID")]
[TestCase("CustomABC123", ExpectedResult = "Custom ABC123")]
public string CanSplitCamelCase(string input)
{
return FromCamelCaseToSentence(input);
}
Хороший ответ. В моем проекте я добавил bool nextIsLower = i > 0 && i + 1 < source.Length && char.IsLower(source[i + 1]); и изменил выражение if на if ((!upper || nextIsLower) && isUpperOrDigit). Это отделяет аббревиатуры от слов, поэтому CustomABCWith123 становится Пользовательский ABC с 123 вместо Пользовательский ABC с 123. Могут быть дела, которыми я не занимался, и, конечно, мы с А не работаем.
Дело верблюда ожидает обратной связи, а не ожидает обратной связи (случай Паскаля). Кроме того, то, что вы хотите делать, не совсем возможно. Как насчет отключения GPS? Есть ли достаточно общее решение для таких случаев?