【问题标题】:Convert Dash-Separated String to camelCase via C#通过 C# 将破折号分隔的字符串转换为驼峰式
【发布时间】:2015-07-07 19:19:50
【问题描述】:

我有一个大型 XML 文件,其中包含实现破折号分隔命名约定的标记名称。如何使用 C# 将标签名称转换为驼峰命名约定?

规则是: 1.将所有字符转换为小写 2.每个破折号之后的第一个字符大写 3.删除所有破折号

示例 转化前

<foo-bar>
 <a-b-c></a-b-c>
</foo-bar>

转换后

<fooBar>
 <aBC></aBC>
</fooBar>

这是一个有效的代码示例,但处理起来很慢 - 我认为有更好的方法来实现我的目标。

string ConvertDashToCamelCase(string input)
{
    input = input.ToLower();
    char[] ca = input.ToCharArray();
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < ca.Length; i++)
    {
        if(ca[i] == '-')
        {
            string t = ca[i + 1].ToString().toUpper();
            sb.Append(t);
            i++;
        }
        else
        {
            sb.Append(ca[i].ToString());
        }
    }

    return sb.ToString();
}

【问题讨论】:

  • 提供一些代码以便我们为您提供帮助...我们不会为您完成这项工作。
  • 好的 - 添加到我的 OP 中的代码示例。正如你所看到的,我强行通过角色。这种方法有效,但速度很慢。我希望找到一个更清洁、更快捷的解决方案。
  • http://stackoverflow.com/questions/17186641/... 的可能重复项,但大写字母后删除了特殊字符。

标签: c# regex string-conversion


【解决方案1】:

您的原始代码运行缓慢的原因是您不必要地到处调用ToString。没有必要这样做。也不需要char 的中间数组。下面的应该比使用String.Split的版本快很多,也快。

string ConvertDashToCamelCase(string input)
{
    StringBuilder sb = new StringBuilder();
    bool caseFlag = false;
    for (int i = 0; i < input.Length; ++i)
    {
        char c = input[i];
        if (c == '-')
        {
            caseFlag = true;
        }
        else if (caseFlag)
        {
            sb.Append(char.ToUpper(c));
            caseFlag = false;
        }
        else
        {
            sb.Append(char.ToLower(c));
        }
    }
    return sb.ToString();
}

我不会声称上述方法是最快的。事实上,有几个明显的优化可以节省一些时间。但以上内容清晰明了:易于理解。

键是caseFlag,用于指示复制的下一个字符应设置为大写。另请注意,我不会自动将整个字符串转换为小写。没有理由这样做,因为无论如何您都会查看每个字符并且可以在那时进行适当的转换。

这里的想法是代码不会做比它绝对必须做的更多的工作。

【讨论】:

  • 需要注意的是,该方法也可以转换为PascalCase,只需在开始时将caseFlag初始化为true即可。
【解决方案2】:
string ConvertDashToCamelCase(string input)
{
    string[] words = input.Split('-');

    words = words.Select(element => wordToCamelCase(element));

    return string.Join("", words);
}

string wordToCamelCase(string input)
{
    return input.First().ToString().ToUpper() + input.Substring(1).ToLower();
}

【讨论】:

  • 我没有机器可以试用此代码,但可以使用&lt;foo-bar&gt;tag-content&lt;/foo-bar&gt; 之类的标签吗?也就是说,如果标签包含一个本身带有连字符的值怎么办?
  • @s.m.:此代码和 OP 的代码假定您要对整个字符串进行转换。如果您想对标签而不是内容进行驼峰式大小写,则必须自己将它们分开。
  • @JimMischel OP 明确写道“如何使用 C# 将 标签名称 转换为驼峰式命名约定?”。这就是为什么我想警告可能破坏 XML 内容的原因,OP 可能没有想到这一点。换句话说,我提供了一双额外的眼睛。
  • @s.m.我正在解析的 XML 文件恰好没有任何内容。所以,Jim 的解决方案很棒。但是,您是对的 - Jim 的解决方案将驼峰式命名所有标签和内容。
  • @s.m. - 我添加并回答说是 Jim Mischel 代码的更新版本,它只会驼峰化 XML 标签名称(而不是内容)。
【解决方案3】:

为了完整起见,这里还有一个正则表达式单行(由this JavaScript answer 启发):

string ConvertDashToCamelCase(string input) =>
    Regex.Replace(input, "-.", m => m.Value.ToUpper().Substring(1));

它将所有出现的-x 替换为转换为大写的x


特殊情况:

  • 如果您想要所有其他字符小写,请将表达式中的 input 替换为 input.ToLower()

      string ConvertDashToCamelCase(string input) =>
          Regex.Replace(input.ToLower(), "-.", m => m.Value.ToUpper().Substring(1));
    
  • 如果您想支持单词之间的多个破折号 (dash--case) 并删除所有破折号 (dashCase),请在正则表达式中将 - 替换为 -+(贪婪匹配所有破折号序列) 并只保留最后一个字符:

      string ConvertDashToCamelCase(string input) =>
          Regex.Replace(input, "-+.", m => m.Value.ToUpper().Substring(m.Value.Length - 1));
    
  • 如果您想支持单词之间的多个破折号 (dash--case) 并只删除最后一个 (dash-Case),请将正则表达式更改为仅匹配一个破折号后跟一个非破折号(而不是一个破折号后面任何字符):

      string ConvertDashToCamelCase(string input) =>
          Regex.Replace(input, "-[^-]", m => m.Value.ToUpper().Substring(1));
    

【讨论】:

  • 澄清一下:对于小写替代方案,input.ToLower() 将是Replace 的第一个参数(通过 表达式,有人可以理解 Linq 求值器)。跨度>
  • @Andrew:好点,我在回答中添加了一个明确的例子。
【解决方案4】:

这是@Jim Mischel 的答案的更新版本,它将忽略内容 - 即它只会驼峰式标记名称。

string ConvertDashToCamelCase(string input)
{
    StringBuilder sb = new StringBuilder();
    bool caseFlag = false;
    bool tagFlag = false; 
    for(int i = 0; i < input.Length; i++)
    {   
        char c = input[i];
        if(tagFlag)
        {
            if (c == '-')
            {
                caseFlag = true;
            }
            else if (caseFlag)
            {
                sb.Append(char.ToUpper(c));
                caseFlag = false;
            }
            else
            {
                sb.Append(char.ToLower(c));
            }
        }
        else
        {
            sb.Append(c);
        }

        // Reset tag flag if necessary
        if(c == '>' || c == '<')
        {
            tagFlag = (c == '<');
        }

    }
    return sb.ToString();
}

【讨论】:

  • 我认为您需要在输入标签时重置caseFlag。否则,&lt;foo-&gt;content&lt;/foo-&gt;&lt;bar&gt;xxx&lt;/bar&gt; 之类的内容将导致 &lt;foo&gt;content&lt;/foo&gt;&lt;Bar&gt;xxx&lt;/bar&gt;(即 bar 标记将大写)。我的函数遇到了同样的问题,因为我对您的要求的理解是您将标签名称传递给函数,而不是一整行 XML 文本。
  • @JimMischel - 原来caseFlag设置为true后,最终会有一个char是结束标签(>)。并且当 char 是结束标记时,满足“else if (caseFlag)”条件。这意味着 caseFlag 将始终重置为 false。换句话说,您的代码可以正常工作。
【解决方案5】:
using System;
using System.Text;

public class MyString
{
  public static string ToCamelCase(string str)
  {
    char[] s = str.ToCharArray();
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < s.Length; i++)
    {
      if (s[i] == '-' || s[i] == '_')
        sb.Append(Char.ToUpper(s[++i]));
      else
        sb.Append(s[i]);
    }
    return sb.ToString();
  }
}

【讨论】:

  • 不鼓励只回答代码,您应该在回答中解释代码,以便用户了解您在做什么以及为什么
猜你喜欢
  • 2012-05-12
  • 2012-01-20
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-20
相关资源
最近更新 更多