【问题标题】:How can I convert text to Pascal case?如何将文本转换为 Pascal 大小写?
【发布时间】:2013-09-05 03:11:32
【问题描述】:

我有一个变量名,比如“WARD_VS_VITAL_SIGNS”,我想将其转换为 Pascal 大小写格式:“WardVsVitalSigns”

WARD_VS_VITAL_SIGNS -> WardVsVitalSigns

如何进行这种转换?

【问题讨论】:

  • 你真的需要使用正则表达式,或者没有正则表达式的方法可以吗?
  • 如果你有一个问题,如果你想使用正则表达式来解决这个问题,你现在有两个问题。 ;-)
  • @AshishGupta ;-) 你是对的,我确实让问题变得更复杂,用 RegEx 来解决。

标签: c# pascalcasing case-conversion


【解决方案1】:

你不需要正则表达式。

var yourString = "WARD_VS_VITAL_SIGNS".ToLower().Replace("_", " ");
TextInfo info = CultureInfo.CurrentCulture.TextInfo;
yourString = info.ToTitleCase(yourString).Replace(" ", string.Empty);
Console.WriteLine(yourString);

【讨论】:

    【解决方案2】:

    这是我的快速 LINQ 和正则表达式解决方案,以节省某人的时间:

    using System;
    using System.Linq;
    using System.Text.RegularExpressions;
    
    public string ToPascalCase(string original)
    {
        Regex invalidCharsRgx = new Regex("[^_a-zA-Z0-9]");
        Regex whiteSpace = new Regex(@"(?<=\s)");
        Regex startsWithLowerCaseChar = new Regex("^[a-z]");
        Regex firstCharFollowedByUpperCasesOnly = new Regex("(?<=[A-Z])[A-Z0-9]+$");
        Regex lowerCaseNextToNumber = new Regex("(?<=[0-9])[a-z]");
        Regex upperCaseInside = new Regex("(?<=[A-Z])[A-Z]+?((?=[A-Z][a-z])|(?=[0-9]))");
    
        // replace white spaces with undescore, then replace all invalid chars with empty string
        var pascalCase = invalidCharsRgx.Replace(whiteSpace.Replace(original, "_"), string.Empty)
            // split by underscores
            .Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries)
            // set first letter to uppercase
            .Select(w => startsWithLowerCaseChar.Replace(w, m => m.Value.ToUpper()))
            // replace second and all following upper case letters to lower if there is no next lower (ABC -> Abc)
            .Select(w => firstCharFollowedByUpperCasesOnly.Replace(w, m => m.Value.ToLower()))
            // set upper case the first lower case following a number (Ab9cd -> Ab9Cd)
            .Select(w => lowerCaseNextToNumber.Replace(w, m => m.Value.ToUpper()))
            // lower second and next upper case letters except the last if it follows by any lower (ABcDEf -> AbcDef)
            .Select(w => upperCaseInside.Replace(w, m => m.Value.ToLower()));
    
        return string.Concat(pascalCase);
    }
    

    示例输出:

    "WARD_VS_VITAL_SIGNS"          "WardVsVitalSigns"
    "Who am I?"                    "WhoAmI"
    "I ate before you got here"    "IAteBeforeYouGotHere"
    "Hello|Who|Am|I?"              "HelloWhoAmI"
    "Live long and prosper"        "LiveLongAndProsper"
    "Lorem ipsum dolor..."         "LoremIpsumDolor"
    "CoolSP"                       "CoolSp"
    "AB9CD"                        "Ab9Cd"
    "CCCTrigger"                   "CccTrigger"
    "CIRC"                         "Circ"
    "ID_SOME"                      "IdSome"
    "ID_SomeOther"                 "IdSomeOther"
    "ID_SOMEOther"                 "IdSomeOther"
    "CCC_SOME_2Phases"             "CccSome2Phases"
    "AlreadyGoodPascalCase"        "AlreadyGoodPascalCase"
    "999 999 99 9 "                "999999999"
    "1 2 3 "                       "123"
    "1 AB cd EFDDD 8"              "1AbCdEfddd8"
    "INVALID VALUE AND _2THINGS"   "InvalidValueAnd2Things"
    

    【讨论】:

    • 这个答案没有足够的支持。不错的实用程序。谢谢!
    • 是的,这个或其他一些有效的版本(不确定是否可以在没有正则表达式的情况下实现它)应该是 .NET 的一部分
    • 这个答案太复杂了,不能很快。此外,对于如何以有效的方式处理正则表达式中的字符类也没有真正的理解。我在下面的回答中展示了如何更有效地进行这种替换。
    【解决方案3】:

    首先,您要的是标题大小写而不是驼峰式,因为在驼峰式中,单词的第一个字母是小写的,而您的示例显示您希望第一个字母为大写。

    无论如何,您可以通过以下方式实现您想要的结果:

    string textToChange = "WARD_VS_VITAL_SIGNS";
    System.Text.StringBuilder resultBuilder = new System.Text.StringBuilder();
    
    foreach(char c in textToChange)
    {
        // Replace anything, but letters and digits, with space
        if(!Char.IsLetterOrDigit(c))
        {
            resultBuilder.Append(" ");
        }
        else 
        { 
            resultBuilder.Append(c); 
        }
    }
    
    string result = resultBuilder.ToString();
    
    // Make result string all lowercase, because ToTitleCase does not change all uppercase correctly
    result = result.ToLower();
    
    // Creates a TextInfo based on the "en-US" culture.
    TextInfo myTI = new CultureInfo("en-US",false).TextInfo;
    
    result = myTI.ToTitleCase(result).Replace(" ", String.Empty);
    

    注意:result 现在是 WardVsVitalSigns

    如果你确实想要驼峰式,那么在上述所有之后,只需使用这个辅助函数:

    public string LowercaseFirst(string s)
    {
        if (string.IsNullOrEmpty(s))
        {
            return string.Empty;
        }
    
        char[] a = s.ToCharArray();
        a[0] = char.ToLower(a[0]);
    
        return new string(a);
    }
    

    所以你可以这样称呼它:

    result = LowercaseFirst(result);
    

    【讨论】:

    • 为什么这不使结果 = Wardvsvitalsigns?
    • @KarlAnderson,感谢您的详细回答,这很有帮助。 ;-)
    • @KarlAnderson if(!Char.IsLetterOrDigit(c)) { resultBuilder.Append(" "); } 应该是if (!Char.IsLetterOrDigit(c)) { resultBuilder.Append(" "); } else { resultBuilder.Append(c); },否则,resultBuilder 总是为空的。 ;-)
    • 我认为从技术上讲它被称为 Pascal case(或 Upper camel case)
    • @Benjol 谢谢提醒,我会更新问题的。
    【解决方案4】:

    单分号解法:

    public static string PascalCase(this string word)
    {
        return string.Join("" , word.Split('_')
                     .Select(w => w.Trim())
                     .Where(w => w.Length > 0)
                     .Select(w => w.Substring(0,1).ToUpper() + w.Substring(1).ToLower()));
    }
    

    【讨论】:

    • 不确定这是什么意图,但这肯定不会导致 PascalCase。 PascalCase 不包含空格...
    • 这是连接文本的每一点,不要看到空格
    • 我写这篇文章已经 5 年了,但我同意,我真的不知道空间问题是什么。它在下划线处拆分,修剪空格,过滤掉任何长度为零的字符串,然后将第一个大写并小写其余部分,然后使用 string.join 将所有内容重新组合在一起(应该在下面使用字符串生成器)。嗯!
    【解决方案5】:

    使用SystemSystem.Linq 与.NET Core 兼容代码的System.String 的扩展方法。

    是否修改原始字符串。

    .NET Fiddle for the code below

    using System;
    using System.Linq;
    
    public static class StringExtensions
    {
        /// <summary>
        /// Converts a string to PascalCase
        /// </summary>
        /// <param name="str">String to convert</param>
    
        public static string ToPascalCase(this string str){
    
            // Replace all non-letter and non-digits with an underscore and lowercase the rest.
            string sample = string.Join("", str?.Select(c => Char.IsLetterOrDigit(c) ? c.ToString().ToLower() : "_").ToArray());
    
            // Split the resulting string by underscore
            // Select first character, uppercase it and concatenate with the rest of the string
            var arr = sample?
                .Split(new []{'_'}, StringSplitOptions.RemoveEmptyEntries)
                .Select(s => $"{s.Substring(0, 1).ToUpper()}{s.Substring(1)}");
    
            // Join the resulting collection
            sample = string.Join("", arr);
    
            return sample;
        }
    }
    
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("WARD_VS_VITAL_SIGNS".ToPascalCase()); // WardVsVitalSigns
            Console.WriteLine("Who am I?".ToPascalCase()); // WhoAmI
            Console.WriteLine("I ate before you got here".ToPascalCase()); // IAteBeforeYouGotHere
            Console.WriteLine("Hello|Who|Am|I?".ToPascalCase()); // HelloWhoAmI
            Console.WriteLine("Live long and prosper".ToPascalCase()); // LiveLongAndProsper
            Console.WriteLine("Lorem ipsum dolor sit amet, consectetur adipiscing elit.".ToPascalCase()); // LoremIpsumDolorSitAmetConsecteturAdipiscingElit
        }
    }
    

    【讨论】:

      【解决方案6】:
      var xs = "WARD_VS_VITAL_SIGNS".Split('_');
      
      var q =
      
          from x in xs
      
          let first_char = char.ToUpper(x[0]) 
          let rest_chars = new string(x.Skip(1).Select(c => char.ToLower(c)).ToArray())
      
          select first_char + rest_chars;
      

      【讨论】:

        【解决方案7】:

        有些答案是正确的,但我真的不明白为什么他们首先将文本设置为小写,因为ToTitleCase 会自动处理:

        var text = "WARD_VS_VITAL_SIGNS".Replace("_", " ");
        
        TextInfo textInfo = CultureInfo.CurrentCulture.TextInfo;
        text = textInfo.ToTitleCase(text).Replace(" ", string.Empty);
        
        Console.WriteLine(text);
        

        【讨论】:

        • 因为 ToTitleCase 在许多用例中效率不高,请在当前页面查看此answer
        • ToTitleCase 不会使其他字符小写,至少在我只需要它的 .NET Core 3.1 中不会。所以必须先做一个ToLower,然后它是正确的。
        【解决方案8】:

        你可以用这个:

        public static string ConvertToPascal(string underScoreString)
            {
                string[] words = underScoreString.Split('_');
        
                StringBuilder returnStr = new StringBuilder();
        
                foreach (string wrd in words)
                {
                    returnStr.Append(wrd.Substring(0, 1).ToUpper());
                    returnStr.Append(wrd.Substring(1).ToLower());
        
                }
                return returnStr.ToString();
            }
        

        【讨论】:

          【解决方案9】:

          此答案了解在处理文本时可以点击 Unicode 类别以忽略连接字符,例如 -_。在正则表达式中,它是\p(用于类别)然后是{Pc} 用于punctuationconnector 类型字符的类型; \p{Pc} 使用我们的 MatchEvaluator,它为会话中的每场比赛启动。

          所以在匹配阶段,我们获取单词并忽略标点符号,因此替换操作处理连接符的删除。一旦我们有了匹配词,我们可以将其向下推到小写,然后只将第一个字符向上大写作为替换的返回:

          public static class StringExtensions
          {
              public static string ToPascalCase(this string initial)
                  => Regex.Replace(initial, 
                                 // (Match any non punctuation) & then ignore any punctuation
                                   @"([^\p{Pc}]+)[\p{Pc}]*", 
                                   new MatchEvaluator(mtch =>
                  {
                      var word = mtch.Groups[1].Value.ToLower();
          
                      return $"{Char.ToUpper(word[0])}{word.Substring(1)}";
                  }));
          }
          

          用法:

          "TOO_MUCH_BABY".ToPascalCase(); // TooMuchBaby
          "HELLO|ITS|ME".ToPascalCase();  // HelloItsMe
          

          Word Character in Character Classes in Regular Expressions

          PC 标点符号,连接器。此类别包括十个字符, 其中最常用的是LOWLINE字符(_),u+005F。

          【讨论】:

          • 你用“AlreadyPascalCase”测试过吗 :)
          【解决方案10】:

          添加ToLower() 后,我发现this gist 很有用。

          "WARD_VS_VITAL_SIGNS".ToLower().Split(new [] {"_"}, StringSplitOptions.RemoveEmptyEntries).Select(s => char.ToUpperInvariant(s[0]) + s.Substring(1, s.Length - 1)).Aggregate(string.Empty, (s1, s2) => s1 + s2)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-27
            • 1970-01-01
            • 2011-11-05
            • 2022-05-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多