Number of occurrences of a character in a string
我试图得到某个字符的出现次数,比如下面的字符串中的&。
1
| string test ="key1=value1&key2=value2&key3=value3"; |
如何确定上述测试字符串变量中有2个和号(&;)。
- 为什么正则表达式????????
- @因为有些人在遇到问题时会想"我知道,我会用正则表达式"。
- @ Tanzelax。像这个?-)
- 这里有更多有趣的答案,尽管它们处理字符串中的字符和字符串。包括基准等。
- 看看stackoverflow.com/questions/541954/…
- "显然不是重复的,因为这篇文章想计算一个字符而不是一个字符串。尽管如此,应当注意的是,包括已接受的答案在内,链接邮件中的大多数答案都是错误的。(因为它们不计算字符串的出现,而是字符。)错误+错误=正确,但仍然是So最黑暗和最令人困扰的地方之一。
- @Tanzelax和那些同样的人也经常会想,"废话,现在我有两个问题。"
你可以这样做:
1
| int count = test.Split('&').Length - 1; |
或与LINQ:
1
| test.Count(x => x == '&'); |
- 值得注意的是,如果字符串很大,第一种方法可能非常昂贵。最坏的情况是,如果字符串很大并且(几乎)完全由重复的分隔符(&;)组成,则由于.NET中的对象开销,它可以分配12-24x原始字符串大小。我将使用第二种方法,如果速度不够快,那么编写一个for循环。
因为LINQ可以做所有的事情……
1 2
| string test ="key1=value1&key2=value2&key3=value3";
var count = test.Where(x => x == '&').Count(); |
或者,如果愿意,可以使用带谓词的Count重载:
1
| var count = test.Count(x => x == '&'); |
- Linq做任何事情的速度都比较慢。如果您想要快速代码,请查看此网页中的基准测试。
- @freecoder24这不是linq的问题,而是一个糟糕的编译器。例如,该示例应该被内联到一个简单的循环(就像它在C++和Haskell中所做的那样)。
- @FreeCoder24,就像C比所有组件都慢一样。如果需要快速代码,请使用程序集。顺便说一句,Linq在排序上比"本机"框架方法更快。
最直接和最有效的方法是简单地循环字符串中的字符:
1 2 3 4
| int cnt = 0;
foreach (char c in test) {
if (c == '&') cnt++;
} |
您可以使用LINQ扩展来制作一个更简单、更高效的版本。开销有点大,但它仍然令人惊讶地接近性能循环:
1
| int cnt = test.Count(c => c == '&'); |
还有一个老的Replace技巧,但是它更适合于循环很笨拙(sql)或缓慢(vbscript)的语言:
1
| int cnt = test.Length - test.Replace("&","").Length; |
- 令人惊讶的是,只有非常小的干草堆才能在性能上接近循环。
- @taw:我看不到短字符串和长字符串(1MB)之间有显著的速率差异,但出于某种原因,X64模式的速率差异比X86模式的速率差异更大。
- 我没有测试char-count版本,但是linq字符串计数随着字符串长度的增加而越来越慢,最后死于一个oom异常。不过,1MB还不是问题。
- @陶:我用2tb的线试过了,效果很好。再大一点,我在创建字符串时会得到一个OOM异常。
- 好吧,那么我猜只有字符串计数会崩溃。看到这里
- @太:如果其中一些断了,用更大的线也就不足为奇了。使用Replace的解决方案创建另一个可以与原始字符串一样大的字符串,Split创建的字符串数组可以与原始字符串一样大,Regex.Matches为找到的每个字符串创建Match对象,Select(Substring())创建的字符串数量非常多。
- 根据这些性能测试,直接for循环比任何LINQ方法都是最好的执行者。
- "最有效",我不同意,绳子越长越慢。然而,你最后的答案"旧的替换技巧"是"几乎"最好的。10秒对长串5秒。使用字符串拆分的方法只短了毫秒。
- @pawelcioch:绳子越长,速度就越慢。如果不处理所有字符串,就没有处理所有字符串的神奇方法。
- @Guffa是的,但从长远来看,由于我在研究性能重要的代码,我测试了所有组合,替换、拆分方法或使用indexof算法总是比遍历字符串或char数组和检查每个char是否相等更快。另外,我的评论并不是要把你置于不利的境地,但关于"循环最有效"的说法是不正确的,作为一个可以让我们寻找性能解决方案的人的前车之鉴,但我同意这是"最直接的"。谢谢!
- @帕韦尔奇奇:你的性能测试肯定有问题。Replace、Split或IndexOf不能比遍历字符串并检查每个字符更快,因为这正是它们所做的,只是增加了额外的开销。
为什么要用regex呢?String实现IEnumerable,所以您只需使用linq。
1
| test.Count(c => c == '&') |
字符串示例类似于get的查询字符串部分。如果是这样,请注意httpContext对您有一些帮助
1
| int numberOfArgs = HttpContext.Current.QueryString.Count; |
有关可以使用querystring执行的操作的更多信息,请参见NameValueCollection。
这是最低效的方法来获得所有答案的计数。但你会得到一本字典,其中包含作为奖励的键值对。
1 2 3 4 5 6 7
| string test ="key1=value1&key2=value2&key3=value3";
var keyValues = Regex.Matches(test, @"([\w\d]+)=([\w\d]+)[&$]*")
.Cast<Match>()
.ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value);
var count = keyValues.Count - 1; |
- 哈哈,"最低效的方式",爱它!
- 在codegolf.stackexchange.com上把它作为一个带Q&A标签的code-trolling。