如何使用LINQ在C#中从字符串中获取首字母缩略词?

9

以下是我如何编写一个Java风格的缩略词函数:

    string makeAcronym(string str)
    {
        string result = "";
        for (int i = 0; i < str.Length; i++)
        {
            if (i == 0 && str[i].ToString() != " ")
            {
                result += str[i];
                continue;
            }

            if (str[i - 1].ToString() == " " && str[i].ToString() != " ")
            {
                result += str[i];
            }
        }

        return result;
    }

是否有更优雅的方式可以使用LINQ或者一些内置的C#函数来完成?

6个回答

15

以下是几个选项

A .NET 4仅适用的选项,使用string.Join:

 string acronym = string.Join(string.Empty,
      input.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries).Select(s => s[0])
      );

在.NET 3.5(或4.0)中,您可以执行以下操作:

 string acronym = new string(input.Split(new[] {' '}, 
      stringSplitOptions.RemoveEmptyEntries).Select(s => s[0]).ToArray());

另一个选项(我个人的选择),基于你原来的逻辑:

 string acronym = new string(
      input.Where( (c,i) => c != ' ' && (i == 0 || input[i-1] == ' ') )
      .ToArray()
    );

你需要在Select之后加上.ToArray()。(除非.net4不再需要这种转换...我不确定) - spender
@spender:不支持.NET 4(它们最终在IEnumerable上添加了join)-仅限于3.5... http://msdn.microsoft.com/en-us/library/dd783876.aspx - Reed Copsey
在示例1中似乎有一个多余的逗号,这仍然无法编译通过。 - Steve Townsend
没问题,你还是得到了+1的 :-) - Steve Townsend

8

这是一种我之前没有看到过的技巧。它基于这样一个假设:字符串中应该缩写的所有字母(仅限这些字母)都是大写的。

string MakeAcronym(string input)
{
    var chars = input.Where(Char.IsUpper).ToArray();
    return new String(chars);
}

// MakeAcronym("Transmission Control Protocol") == "TCP"

5
你可以使用Regex / Linq组合来完成这个任务:
您可以使用Regex / Linq组合轻松完成此操作:
String
    .Join("",
        Regex
            .Matches("this is a test",@"(?<=^| )\w")
            .Cast<Match>()
            .Select(m=>m.Value)
            .ToArray()
    )

2
你真的需要正则表达式吗?Char.IsWhitespace怎么样? - Nick Heiner
1
不,你可能不需要正则表达式,但它确实可以让你更好地控制单词之间的空格表示。如果列表增加了标点符号(例如),正则表达式可能是解决这个问题最简洁的方法。可能会有用。 - spender

4
您可以使用LINQ的Aggregate方法以相当优雅的方式完成此操作。
类似于以下内容:
private static string MakeAcronym2(string str)
{
    return str.Split(' ').Aggregate("", (x, y) => x += y[0]);
}

1
我对StringBuilder在实践中会明显更快的观点提出质疑。 - mtreit
@CodeInChaos:另外,你能给出一个导致失败的输入示例吗?我不太确定我同意你的空子字符串说法。谢谢! - mtreit
@CodeInChaos:我认为你错了。试一下就知道了。 - mtreit
1
我刚在LinqPad中尝试了一下,两者都抛出了IndexOutOfRange异常。 - CodesInChaos
@CodeInChaos:是的,你说得对。我的测试程序有一个掩盖了这个问题的错误。 - mtreit
显示剩余2条评论

2

LINQ可以实现这个功能,但通常我发现最好使用StringBuilder实例来构建string值。这样可以避免不必要的string分配。

string makeAcronym(string str) { 
  var builder = new StringBuilder();
  for ( var i = 0; i < str.Length; i++ ) { 
    var c = str[i];
    if ( c == ' ' ) {
      continue;
    }
    if ( i == 0 || str[i-1] == ' ' ) {
      builder.Append(c);
    }
  }
  return builder.ToString();
}

@Reed,不一定。我甚至考虑将循环的内部部分作为LINQ查询来返回要放入构建器中的“char”(我只是变懒了,用了for循环)。我想要强调的唯一性能方面是它不会分配任何中间字符串。 - JaredPar
我重新阅读了你的评论后意识到这一点,所以删除了我的评论 ;) 不过我同意,在这里消除中间字符串非常重要。 - Reed Copsey

0
string makeAcronym(string str)
{
    return new string(str.Split(new [] {' '}, 
        StringSplitOptions.RemoveEmptyEntries).Select(s => s[0]).ToArray());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接