将Pascal Case转换为句子的最佳方法


75

从Pascal Case(上驼峰式案例)转换为句子的最佳方法是什么。

例如以

"AwaitingFeedback"

并将其转换为

"Awaiting feedback"

最好使用C#,但我可以将其从Java或类似版本进行转换。


2
骆驼案在等待反馈,而不是在等待反馈(帕斯卡案)。另外,您想做的事情也不是完全可能的。禁用GPS怎么样?是否有足够通用的解决方案来处理这些情况?
kgiannakakis

@kgiannakakis相应地更改了问题。我总是会忘记名字的周围,尤其是上面和下面的驼色保护套。
加里·舒特勒

Answers:


71
public static string ToSentenceCase(this string str)
{
    return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}

在2015年之后的Visual Studio版本中,您可以

public static string ToSentenceCase(this string str)
{
    return Regex.Replace(str, "[a-z][A-Z]", m => $"{m.Value[0]} {char.ToLower(m.Value[1])}");
}

基于:使用正则表达式将Pascal大小写转换为句子


16

这对我有用:

Regex.Replace(strIn, "([A-Z]{1,2}|[0-9]+)", " $1").TrimStart()

5
这如何改变空格后字母的大小写?
德鲁·诺阿克斯

1
对于诸如AwaitingTFeedback或的情况,这可能无法返回您的预期Awaiting9Feedback杰夫的答案对我来说更好(分别返回Awaiting T FeedbackAwaiting9 Feedback)。
nawfal

16

我更喜欢使用Humanizer。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));
        }
    }
}

输出量

等待反馈

Pascal大小写输入字符串变成句子

下划线的输入字符串变成句子可以返回标题大小写

可以返回小写

如果您喜欢编写自己的C#代码,则可以通过编写一些已经被其他人答复的C#代码来实现。


15

干得好...

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

1
您应该ToUpper()第一个字符,否则您的例程将无法使用真正的camelCase,只能使用PascalCase
David Wengier,

是的,不错,当他说“ AwaitingFeedback”是骆驼案时,我知道有些不对劲(但是我不能动弹)。
Autodidact

9

就像@SSTA一样,但是比调用TrimStart更有效。

Regex.Replace("ThisIsMyCapsDelimitedString", "(\\B[A-Z])", " $1")

9

在MvcContrib源代码中找到了它,这里似乎还没有提到。

return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();

4

这是我使用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();
}

它还会拆分一些我没有指定但有用的数字。


4

仅仅因为每个人都在使用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();
}

2

我将使用正则表达式,在每个大写字符之前插入一个空格,然后放下所有字符串。

    string spacedString = System.Text.RegularExpressions.Regex.Replace(yourString, "\B([A-Z])", " \k");
    spacedString = spacedString.ToLower();

我不了解C#,但我认为替换部分中的\ s这样的转义符是合法的:该语言如何知道是否必须插入空格,制表符或其他内容?:-)
PhiLho

没错,应该以简单的“”代替它。
Antoine

我唯一要说的是会产生“等待反馈”
Garry Shutler,

好吧,您一定要删除第一个空格并将第一个字符放在上方。也许在模式之前添加“ \ B”,以免与第一个字符匹配。
安托万

2
string camel = "MyCamelCaseString";
string s = Regex.Replace(camel, "([A-Z])", " $1").ToLower().Trim();
Console.WriteLine(s.Substring(0,1).ToUpper() + s.Substring(1));

编辑:没有注意到您的机壳要求,因此进行了修改。您可以使用matchevaluator进行大小写,但我认为子字符串更容易。您也可以将其包装在第二个正则表达式替换中,以更改第一个字符

"^\w"

\U (i think)

2

在JavaScript(或PHP等)中很容易做到,您可以在replace调用中定义一个函数:

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

请注意在不损失任何字符的情况下拆分句子的技巧。


1

伪代码:

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


1

一个适用于UpperCamel和LowerCamel案例的xquery解决方案:

要输出句子大小写(仅将第一个单词的第一个字符大写):

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

1

发现自己做了类似的事情,因此,我很高兴能与您讨论这个问题。这是我的解决方案,在控制台应用程序的上下文中作为字符串类的扩展方法。

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

1

前面的大多数答案都会将首字母缩写词和数字分开,并在每个字符前添加一个空格。我希望首字母缩写词和数字保持在一起,所以我有一个简单的状态机,每次输入从一种状态转换到另一种状态时,该状态机都会发出一个空格。

    /// <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成为Custom ABC With 123而不是Custom ABCWith 123。可能有些情况我没有处理,当然,A和我没有工作。
stritch000 '20

0

大部分已经在这里回答了

对接受的答案进行小修改,将第二个及后续大写字母转换为小写,因此进行更改

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]);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.