将ProperCase转换为标题案例中的句子(与句子案例相对)

时间:2016-04-23 20:53:28

标签: c#

您好我想将一个正确的单词转换为标题中的单词。例如:

NumberOfLoyalHonestWomen将成为

  

忠诚的女性人数

它基本上是一种结合反射的方式,可以在自动生成屏幕输入时将字段/属性名称转换为穷人的标签。

这就是我得到的。有更好或更清洁的方式吗? Dot Net Fiddle

using System;
using System.Text.RegularExpressions;
using System.Linq;

public class Program
{
    public static void Main()
    {
        string testString = "ATCPConnection";
        Console.WriteLine(testString.ToSentence());
    }

}

public static class StringExtensions
{
    public static string ToSentence(this string Source)
    {
        return Regex.Replace(string.Concat(from Char c 
                                           in Source.ToCharArray()
                                           select Char.IsUpper(c) ? " " + c : c.ToString()).Trim(), 
                             "(?<AcronymLetter>[A-Z]) (?=[A-Z](?![a-z]))", 
                             "${AcronymLetter}");
    }

}

旁注:由于我希望保持首字母缩略词的完整性,因此很复杂,因此Regex.Replace。例如:

MGTOWSaysThereAreMoreUnicorns将成为

  

MGTOW表示还有更多的独角兽

4 个答案:

答案 0 :(得分:5)

这是另一种方法:

  1. 在每个大写字母前面插入一个空格,后面紧跟后跟一个小写字母(除非这个字母出现在字符串的开头)。这会在PascalCased单词之前添加空格。
  2. 然后在每个大写字母前面插入一个空格,该字母在前面后面加一个小写字母。这会在ACRONYMS之前添加空格。
  3. 因此:

    C:\Program Files\mingw64>g++ -std=c++11 pracrise.cpp -lpthread
    pracrise.cpp: In function 'int main()':
    pracrise.cpp:25:15: error: 'quick_exit' was not declared in this scope
       quick_exit(0);
                   ^
    

    更新:上面的两个正则表达式可以组合成一行:

    public static string ToSentence(this string Source)
    {
        Source = Regex.Replace(Source, "((?<!^)[A-Z][a-z])", " $1");
        Source = Regex.Replace(Source, "([a-z])([A-Z])", "$1 $2");
        return Source;
    }
    

答案 1 :(得分:3)

这个实现怎么样?

仅供参考:System.Runtime.CompilerServices.ExtensionAttribute不能在C#中使用 (它可以在VB.NET中使用。)

使用this关键字标记方法的第一个参数。

public static string ToSentence(this string value)
{
    char[] characters = value.ToCharArray();

    // Determine where groups start
    List<int> groupStartIndexes =
        characters
            .Select((character, index) =>
                new
                {
                    Character = character,
                    Index = index
                }
            )
            .Where(obj => Char.IsUpper(obj.Character))
            .Select(obj => obj.Index)
            .ToList();

    // if there is no upper case letter or
    // if value does not start with an upper case letter
    if (!groupStartIndexes.Contains(0))
    {
        groupStartIndexes.Insert(0, 0);
    }

    // To make our life easier
    groupStartIndexes.Add(value.Length);

    var groups = new List<string>();

    // Split value into groups
    for (int index = 0; index < groupStartIndexes.Count - 1; index++)
    {
        int currentGroupStartIndex = groupStartIndexes[index];
        int nextGroupStartIndex = groupStartIndexes[index + 1];

        string currentGroup =
            value
                .Substring(
                    currentGroupStartIndex,
                    nextGroupStartIndex - currentGroupStartIndex
                );

        groups.Add(currentGroup);
    }

    var sb = new StringBuilder(groups[0]);

    // Build the final string
    for (int currentGroupIndex = 1; currentGroupIndex < groups.Count; currentGroupIndex++)
    {
        string previousGroup = groups[currentGroupIndex - 1];
        string currentGroup = groups[currentGroupIndex];

        if (previousGroup.Length > 1 || currentGroup.Length > 1)
        {
            sb.Append(" ");
        }

        sb.Append(groups[currentGroupIndex]);
    }

    return sb.ToString();
}

答案 2 :(得分:2)

这似乎是一个有趣的话题。这是我的尝试。

public static string ToSentence(this string src) {
    var retVal = "";
    if (src.Length > 0) {
        List<string> wordCollection = new List<string>();
        int startIndex = 0;
        char[] letters = src.ToCharArray();
        //Skip the First Letter
        var length = letters.Length;
        for (int i = 1; i < length; i++) {
            if (char.IsUpper(letters[i])) {
                //Check for acronyms
                if (char.IsUpper(letters[i - 1])
                    && (
                           i == length - 1 ||
                           ((i + 1) < length && (char.IsUpper(letters[i + 1]) || char.IsNumber(letters[i + 1])))
                        )
                )
                    continue;

                //Grab Eeverything before Current Index
                var temp = new String(letters, startIndex, i - startIndex);
                wordCollection.Add(temp.Trim());
                startIndex = i;
            }
        }
        wordCollection.Add(new String(letters, startIndex, letters.Length - startIndex));
        retVal = String.Join(" ", wordCollection);
    }
    return retVal;
}

以下测试全部通过

   public class TestCases {
        [DataDrivenTestMethod]
        [DataRow("NumberOfLoyalHonestWomen", "Number Of Loyal Honest Women")]
        [DataRow("MGTOWSaysThereAreMoreUnicorns", "MGTOW Says There Are More Unicorns")]
        [DataRow("MGTOW1SaysThereAreMoreUnicorns", "MGTOW1 Says There Are More Unicorns")]
        [DataRow("MGTOWSaysThereAreMOREUnicorns", "MGTOW Says There Are MORE Unicorns")]
        [DataRow("MGTOWSaysThereAREMoreUNICORNS", "MGTOW Says There ARE More UNICORNS")]            
        public void ConvertToTitleCase(string stringUnderTest, string expected) {
            var actual = stringUnderTest.ToSentence();
            Assert.AreEqual(expected, actual);
        }

    }

答案 3 :(得分:1)

这种方法类似于@ Gabor,有一些保障和优化。虽然不可能像@ MichaelLiunot的正则表达式解决方案那样紧凑,但它应该快得多。我已经针对目前给出的所有例子进行了测试。

public static string ToSentence(this string value)
{
    if (value == null) return value;
    int length = value.Length;
    if (length <= 1) return value;

    var sb = new StringBuilder(value[0].ToString(), length);
    char currentChar;

    for (int ubound = length - 2, i = 1; i <= ubound; ++i)
    {
        currentChar = value[i];
        if (Char.IsUpper(currentChar) && (Char.IsLower(value[i - 1]) || Char.IsLower(value[i + 1])))
            sb.Append(' ');
        sb.Append(currentChar);
    }
    currentChar = value[length - 1];
    if (Char.IsUpper(currentChar) && Char.IsLower(value[length - 2]))
        sb.Append(' ');
    sb.Append(currentChar);
    return sb.ToString();
}