我正在做某事,我意识到我想算出我可以在一个字符串中找到多少个/,然后让我吃惊的是,有几种方法可以做到,但无法决定最好的(或最简单的)是。

目前,我正在使用类似的东西:

string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;


但是我一点都不喜欢它,任何参与者?

我真的不想为此掏出RegEx,对吗?

我知道我的字符串将包含我要搜索的术语,所以您可以假设...

对于长度大于1的字符串,当然

string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;


评论

+1:我必须说这是一种非常不同的计算方式。我对基准测试结果感到惊讶:)

没什么不同...这是在SQL中实现此功能的典型方法:LEN(ColumnToCheck)-LEN(REPLACE(ColumnToCheck,“ N”,“”))。

实际上,您应该用“ /”除。长度

请问您的要求是,“ /////”中“ //”出现的次数应该是多少? 2还是4?

使用正则表达式可能是解决此问题的最佳方法

#1 楼

如果您使用的是.NET 3.5,则可以使用LINQ以单线方式执行此操作:

int count = source.Count(f => f == '/');


如果您不想使用LINQ,则可以执行此操作使用:

int count = source.Split('/').Length - 1;



您可能会惊讶地发现,您的原始技术似乎比这两种技术都快30%!我刚刚使用“ / once / upon / a / time /”进行了快速基准测试,结果如下:


您的原始= 12s
source.Count = 19s
source.Split = 17s
foreach(根据bobwienholt的回答)= 10s


(时间为50,000,000次迭代,因此您不太可能注意到很多现实世界中的差异。)

评论


是的,VS在字符串类上隐藏了LINQ扩展方法。我猜他们认为开发人员不希望所有这些扩展方法都出现在字符串类中。可能是一个明智的决定。

–犹大·加布里埃尔·Himango
09年2月15日在23:27

这可能是因为VS2010自动将System.Linq包含在新的类文件中,而VS2008则可能没有。必须使用名称空间才能使智能感知工作。

–斯普拉
2012年7月12日在8:13

请注意,“计数”和“拆分”解决方案仅在计数字符时才有效。它们不能像OP的解决方案那样使用字符串。

– Peter Lillevold
2014年5月7日在9:03

f =='\'是关于字符串中的字符,而不是字符串中的字符串

–托马斯·韦勒(Thomas Weller)
16年8月26日在14:13

这似乎是对另一个问题的答案:“您如何计算字符串中出现的char?”

–本·亚伦森
16年11月28日在13:34

#2 楼

string source = "/once/upon/a/time/";
int count = 0;
foreach (char c in source) 
  if (c == '/') count++;


source.Replace()本身要快。

评论


通过切换为for而不是foreach,您可以获得微不足道的改进,但是只有很小一部分。

–马克
09年2月12日在18:13

不。该问题要求计算字符串(而不是字符)的出现。

–樱樱
2015年12月7日在9:47



这是对字符串中的字符进行计数。标题是关于计算字符串中的字符串

–托马斯·韦勒(Thomas Weller)
16年8月26日在14:11

@Mark刚刚使用for循环对其进行了测试,它实际上比使用foreach慢。可能是因为边界检查? (时间为1.65秒,而500万次迭代为2.05)。

–测量
16 Dec 13'9:05



当问题是在字符串中要求一个字符串时,OP上张贴的示例问题实际上只是一个字符,在这种情况下,我将这个答案称为有效解决方案,因为它显示了一种更好的方法(用字符搜索而不是字符串搜索)解决眼前的问题。

–乍得
17年2月23日在21:39

#3 楼

int count = new Regex(Regex.Escape(needle)).Matches(haystack).Count;


评论


+1-在某些情况下,您可能想添加RegexOptions.IgnoreCase。

– TrueWill
14年6月23日19:31

这难道不是很低吗?

–托马斯·阿尤布(Thomas Ayoub)
15年3月16日在15:31

正则表达式的开销并不理想,再加上“我真的不想为此掏出正则表达式,对吗?”

–乍得
17年2月23日在21:40

可能不想要Regex.Escape(...),所以希望使用新的System.Text.RegularExpressions.Regex(needle).Matches(haystack).Count;

– barlop
19年1月14日在8:57



我选择了这个,因为它可以搜索字符串,而不仅仅是字符。

–詹姆斯·印第(James in Indy)
19年7月1日在13:56

#4 楼

如果您希望能够搜索整个字符串,而不仅仅是字符:

src.Select((c, i) => src.Substring(i))
    .Count(sub => sub.StartsWith(target))


读取字符串中的每个字符时,请提取其余字符串从该字符开始,作为子字符串;如果它以目标字符串开头,则对其进行计数。“

评论


不知道如何用比给定的说明更清楚的方式解释它。什么令人困惑?

–mqp
2012年3月8日20:17

超慢!在html页面上进行了尝试,花费了大约2分钟,而此页面上的其他方法花费了2秒。答案是正确的。太慢了,无法使用。

– JohnB
2012年6月20日在21:51



同意,太慢了。我是linq式解决方案的忠实拥护者,但这是不可行的。

–斯普拉
2012年7月12日在8:09

请注意,之所以这么慢是因为它创建了n个字符串,因此大约分配了n ^ 2/2个字节。

– Peter Crabtree
13年2月7日在19:32

我的210000个字符的字符串抛出OutOfMemoryException。

–ender
2013年9月13日在8:47

#5 楼

我进行了一些研究,发现Richard Watson的解决方案在大多数情况下是最快的。这就是该表中每个解决方案的结果的表格(那些使用Regex的解决方案除外,因为使用Regex的原因是它在解析诸如“ test {test”之类的字符串时会抛出异常)

    Name      | Short/char |  Long/char | Short/short| Long/short |  Long/long |
    Inspite   |         134|        1853|          95|        1146|         671|
    LukeH_1   |         346|        4490|         N/A|         N/A|         N/A|
    LukeH_2   |         152|        1569|         197|        2425|        2171|
Bobwienholt   |         230|        3269|         N/A|         N/A|         N/A|
Richard Watson|          33|         298|         146|         737|         543|
StefanosKargas|         N/A|         N/A|         681|       11884|       12486|


如果在短字符串(10-50个字符)中发现短子字符串(1-5个字符)的出现次数,则首选原始算法。

此外,对于多字符子字符串,您应使用以下代码代码(基于Richard Watson的解决方案)

int count = 0, n = 0;

if(substring != "")
{
    while ((n = source.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
    {
        n += substring.Length;
        ++count;
    }
}


评论


我正要添加自己的“低级”解决方案(不创建子字符串,不使用replace / split或任何Regex / Linq),但是您的解决方案可能比我的更好(至少更短)。谢谢!

– Dan W
2012年8月3日在20:03



对于Regex解决方案,请添加Regex.Escape(needle)

–胸腺嘧啶
2013年6月14日14:57在

只是指出其他问题,需要检查搜索值是否为空,否则您将陷入无限循环。

–WhoIsRich
2014年5月30日晚上11:43

也许只是我,但是对于source =“ aaa” substring =“ aa”我希望得到2,而不是1。要“修复”此问题,请将n + = substring.Length更改为n ++

– ytoledano
16年9月1日在20:35

您可以添加重叠标志来满足您的情况,如下所示:overlayped = True; .... if(overlapped){++ n;} else {n + = substring.Length;}

–tsionyx
16-09-2在11:40

#6 楼

LINQ适用于所有集合,并且由于字符串只是字符的集合,所以这个漂亮的小单行代码怎么样:

var count = source.Count(c => c == '/');


确保顶部有using System.Linq;代码文件,因为.Count是该命名空间的扩展方法。

评论


在那里真的值得使用var吗?是否有可能将Count替换为不返回int的内容?

– Whatsit
09年2月12日在19:01

@Whatsit:您可以只用左手输入“ var”,而“ int”则需要双手;)

– Sean Bright
09年2月12日在22:05

int字母都驻留在主键中,而var则不。嗯..等等,我在用Dvorak

–迈克尔·布恩(Michael Buen)
2010年5月7日14:40

@BDotA确保您具有“正在使用System.Linq;”在文件的顶部。另外,由于它是字符串,因此intellisense可能会向您隐藏.Count调用。即使这样,它也可以编译运行。

–犹大·加布里埃尔·Himango
2012年1月27日19:25

@JudahGabrielHimango我认为应该使用var,尤其是当变量类型很明显时(为了简洁和一致性)。

– EriF89
19年2月22日在15:03

#7 楼

string source = "/once/upon/a/time/";
int count = 0;
int n = 0;

while ((n = source.IndexOf('/', n)) != -1)
{
   n++;
   count++;
}


在我的计算机上,它比进行5000万次迭代的每个字符的解决方案快大约2秒。

2013版本:

更改将字符串转换为char []并对其进行迭代。将总时间再减少一秒或两秒,以进行50m次迭代!

char[] testchars = source.ToCharArray();
foreach (char c in testchars)
{
     if (c == '/')
         count++;
}


这更快:

char[] testchars = source.ToCharArray();
int length = testchars.Length;
for (int n = 0; n < length; n++)
{
    if (testchars[n] == '/')
        count++;
}


从好的角度来说,从数组的末尾到0的迭代似乎最快,大约是5%。

int length = testchars.Length;
for (int n = length-1; n >= 0; n--)
{
    if (testchars[n] == '/')
        count++;
}


我想知道为什么会这样过去和现在都在谷歌搜索(我还记得更快地进行反向迭代),并遇到了这个SO问题,它已经烦人地使用了字符串char []技术。我认为在这种情况下反向技巧是新的。

迭代C#中字符串中各个字符的最快方法是什么?

评论


您可以放置​​source.IndexOf('/',n + 1)并丢失n ++和while括号:)此外,放置可变字符串word =“ /”而不是字符。

–neeKo
2012年12月13日下午4:59

嗨Niko,签出新答案。不过,可变长度子字符串可能更难。

–理查德·沃森(Richard Watson)
13年2月19日在12:14

我通过逐步简化使用了类似的方法。直到我意识到indexOf具有startIndex。我最喜欢第一个解决方案,因为它在速度和内存占用之间保持了良好的平衡。

– Samir Banjanovic
2013年9月30日18:39

我在某处读到,向后迭代的速度更快,因为将值与0进行比较更快

– Reggaeguitar
2015年2月25日在22:46

@shitpoet是的。如果您查看底层代码,那是一个本地调用。 public char [] toCharArray(){... System.arraycopy(value,0,result,0,value.length); ...}

–理查德·沃森(Richard Watson)
18/12/18在12:29



#8 楼

这两个都只适用于单字符搜索项...

countOccurences("the", "the answer is the answer");

int countOccurences(string needle, string haystack)
{
    return (haystack.Length - haystack.Replace(needle,"").Length) / needle.Length;
}


对于较长的针头可能会更好...

但是必须有一种更优雅的方法。 :)

评论


考虑到多字符替换。没有它,在“测试是关键”中计算“ the”将返回6。

–僵尸羊
09年2月12日在16:06

进行基准测试并与string.Split-way进行比较-快约1.5倍。荣誉

– Alex
2014年9月9日22:55

#9 楼

编辑:

source.Split('/').Length-1


评论


这就是我的工作。还有source.Split(new [] {“ //”},StringSplitOptions.None).Count-多字符分隔符为1。

– bzlm
09年10月12日在10:05

这将在堆上执行至少n个字符串分配,加上(可能)几个数组调整大小-所有这些只是为了获得计数?效率极低,无法很好地扩展,永远不要在任何重要的代码中使用。

–扎尔·沙丹(Zar Shardan)
2012年12月13日下午4:16

#10 楼

在C#中,一个不错的String SubString计数器是个异常棘手的家伙:

public static int CCount(String haystack, String needle)
{
    return haystack.Split(new[] { needle }, StringSplitOptions.None).Length - 1;
}


评论


不错的解决方案-也可以用于字符串(不只是char)!

– ChriPf
16年4月19日在6:20

谢谢,在交换语言时,忘记字符串处理的一些细微之处很容易-就像我们今天大多数人一样!

–戴夫
16年4月28日在13:12

-1因为:您知道Count()与Count或Length之间的区别吗?如果有人使用Count()而不是Count或Length,则会被触发。 Count()创建IEnumerator,然后遍历IEnumerable的所有出现,而Count或Length已设置为对象的属性,该属性已保存所需的计数,而无需遍历所有元素。

– Aeroson
17年2月13日在19:04



不错的地方,而且很奇怪的是,在我的函数库中,我从那里开始使用函数“ Length”。编辑!

–戴夫
17年2月14日在8:51

#11 楼

Regex.Matches(input,  Regex.Escape("stringToMatch")).Count


评论


如果输入包含正则表达式特殊字符,即| |,则不正确。需要有一个Regex.Escape(input)

– Esben Skov Pedersen
15年4月24日在7:10

实际上,stringToMatch需要转义,而不是输入。

– Theodor Zoulias
19年5月28日在17:41

你是对的。解决它。

–cederlof
19年5月29日在7:24

#12 楼

private int CountWords(string text, string word) {
    int count = (text.Length - text.Replace(word, "").Length) / word.Length;
    return count;
}


因为最初的解决方案对于chars来说是最快的,所以我想对于字符串来说也是如此。因此,这是我的贡献。

对于上下文:我正在日志文件中查找“失败”和“成功”之类的词。

Gr,


评论


只是不要为“ word”变量传递空字符串(除以零误差)。

–安德鲁·詹斯(Andrew Jens)
18-3-9的2:15

#13 楼

string s = "65 fght 6565 4665 hjk";
int count = 0;
foreach (Match m in Regex.Matches(s, "65"))
  count++;


评论


或Regex.Matches(s,“ 65”)。Count ^ _ ^

–元
11年6月28日在7:29

不适用于每个字符串。尝试在“ abc ++ def ++ xyz”中搜索“ ++”

–沼泽摆动
19年4月30日在21:01



#14 楼

对于想要使用String扩展方法的人,

这里使用的是基于最好的发布答案:

public static class StringExtension
{    
    /// <summary> Returns the number of occurences of a string within a string, optional comparison allows case and culture control. </summary>
    public static int Occurrences(this System.String input, string value, StringComparison stringComparisonType = StringComparison.Ordinal)
    {
        if (String.IsNullOrEmpty(value)) return 0;

        int count    = 0;
        int position = 0;

        while ((position = input.IndexOf(value, position, stringComparisonType)) != -1)
        {
            position += value.Length;
            count    += 1;
        }

        return count;
    }

    /// <summary> Returns the number of occurences of a single character within a string. </summary>
    public static int Occurrences(this System.String input, char value)
    {
        int count = 0;
        foreach (char c in input) if (c == value) count += 1;
        return count;
    }
}


评论


如果传入的字符串为null或为空,则第二种方法不会生效吗?纯粹从样式角度来看,您将输入定义为System.String而不是字符串吗?

– Nodoid
19年4月29日在11:25

#15 楼

public static int GetNumSubstringOccurrences(string text, string search)
{
    int num = 0;
    int pos = 0;

    if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(search))
    {
        while ((pos = text.IndexOf(search, pos)) > -1)
        {
            num ++;
            pos += search.Length;
        }
    }
    return num;
}


#16 楼

我认为最简单的方法是使用正则表达式。这样,您可以获得与使用myVar.Split('x')相同的拆分计数,但使用的是多字符设置。

string myVar = "do this to count the number of words in my wording so that I can word it up!";
int count = Regex.Split(myVar, "word").Length;


#17 楼

string search = "/string";
var occurrences = (regex.Match(search, @"\/")).Count;


每次程序精确地找到“ / s”(区分大小写),此操作都将计数,并且
出现的次数将存储在变量“ occurrences”中

#18 楼

我感到我们缺少某些类型的子字符串计数,例如不安全的逐字节比较。我将原始海报的方法和我能想到的任何方法放在一起。

这些是我做的字符串扩展。

namespace Example
{
    using System;
    using System.Text;

    public static class StringExtensions
    {
        public static int CountSubstr(this string str, string substr)
        {
            return (str.Length - str.Replace(substr, "").Length) / substr.Length;
        }

        public static int CountSubstr(this string str, char substr)
        {
            return (str.Length - str.Replace(substr.ToString(), "").Length);
        }

        public static int CountSubstr2(this string str, string substr)
        {
            int substrlen = substr.Length;
            int lastIndex = str.IndexOf(substr, 0, StringComparison.Ordinal);
            int count = 0;
            while (lastIndex != -1)
            {
                ++count;
                lastIndex = str.IndexOf(substr, lastIndex + substrlen, StringComparison.Ordinal);
            }

            return count;
        }

        public static int CountSubstr2(this string str, char substr)
        {
            int lastIndex = str.IndexOf(substr, 0);
            int count = 0;
            while (lastIndex != -1)
            {
                ++count;
                lastIndex = str.IndexOf(substr, lastIndex + 1);
            }

            return count;
        }

        public static int CountChar(this string str, char substr)
        {
            int length = str.Length;
            int count = 0;
            for (int i = 0; i < length; ++i)
                if (str[i] == substr)
                    ++count;

            return count;
        }

        public static int CountChar2(this string str, char substr)
        {
            int count = 0;
            foreach (var c in str)
                if (c == substr)
                    ++count;

            return count;
        }

        public static unsafe int CountChar3(this string str, char substr)
        {
            int length = str.Length;
            int count = 0;
            fixed (char* chars = str)
            {
                for (int i = 0; i < length; ++i)
                    if (*(chars + i) == substr)
                        ++count;
            }

            return count;
        }

        public static unsafe int CountChar4(this string str, char substr)
        {
            int length = str.Length;
            int count = 0;
            fixed (char* chars = str)
            {
                for (int i = length - 1; i >= 0; --i)
                    if (*(chars + i) == substr)
                        ++count;
            }

            return count;
        }

        public static unsafe int CountSubstr3(this string str, string substr)
        {
            int length = str.Length;
            int substrlen = substr.Length;
            int count = 0;
            fixed (char* strc = str)
            {
                fixed (char* substrc = substr)
                {
                    int n = 0;

                    for (int i = 0; i < length; ++i)
                    {
                        if (*(strc + i) == *(substrc + n))
                        {
                            ++n;
                            if (n == substrlen)
                            {
                                ++count;
                                n = 0;
                            }
                        }
                        else
                            n = 0;
                    }
                }
            }

            return count;
        }

        public static int CountSubstr3(this string str, char substr)
        {
            return CountSubstr3(str, substr.ToString());
        }

        public static unsafe int CountSubstr4(this string str, string substr)
        {
            int length = str.Length;
            int substrLastIndex = substr.Length - 1;
            int count = 0;
            fixed (char* strc = str)
            {
                fixed (char* substrc = substr)
                {
                    int n = substrLastIndex;

                    for (int i = length - 1; i >= 0; --i)
                    {
                        if (*(strc + i) == *(substrc + n))
                        {
                            if (--n == -1)
                            {
                                ++count;
                                n = substrLastIndex;
                            }
                        }
                        else
                            n = substrLastIndex;
                    }
                }
            }

            return count;
        }

        public static int CountSubstr4(this string str, char substr)
        {
            return CountSubstr4(str, substr.ToString());
        }
    }
}


测试代码...

static void Main()
{
    const char matchA = '_';
    const string matchB = "and";
    const string matchC = "muchlongerword";
    const string testStrA = "_and_d_e_banna_i_o___pfasd__and_d_e_banna_i_o___pfasd_";
    const string testStrB = "and sdf and ans andeians andano ip and and sdf and ans andeians andano ip and";
    const string testStrC =
        "muchlongerword amuchlongerworsdfmuchlongerwordsdf jmuchlongerworijv muchlongerword sdmuchlongerword dsmuchlongerword";
    const int testSize = 1000000;
    Console.WriteLine(testStrA.CountSubstr('_'));
    Console.WriteLine(testStrA.CountSubstr2('_'));
    Console.WriteLine(testStrA.CountSubstr3('_'));
    Console.WriteLine(testStrA.CountSubstr4('_'));
    Console.WriteLine(testStrA.CountChar('_'));
    Console.WriteLine(testStrA.CountChar2('_'));
    Console.WriteLine(testStrA.CountChar3('_'));
    Console.WriteLine(testStrA.CountChar4('_'));
    Console.WriteLine(testStrB.CountSubstr("and"));
    Console.WriteLine(testStrB.CountSubstr2("and"));
    Console.WriteLine(testStrB.CountSubstr3("and"));
    Console.WriteLine(testStrB.CountSubstr4("and"));
    Console.WriteLine(testStrC.CountSubstr("muchlongerword"));
    Console.WriteLine(testStrC.CountSubstr2("muchlongerword"));
    Console.WriteLine(testStrC.CountSubstr3("muchlongerword"));
    Console.WriteLine(testStrC.CountSubstr4("muchlongerword"));
    var timer = new Stopwatch();
    timer.Start();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountSubstr(matchA);
    timer.Stop();
    Console.WriteLine("CS1 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrB.CountSubstr(matchB);
    timer.Stop();
    Console.WriteLine("CS1 and: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrC.CountSubstr(matchC);
    timer.Stop();
    Console.WriteLine("CS1 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountSubstr2(matchA);
    timer.Stop();
    Console.WriteLine("CS2 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrB.CountSubstr2(matchB);
    timer.Stop();
    Console.WriteLine("CS2 and: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrC.CountSubstr2(matchC);
    timer.Stop();
    Console.WriteLine("CS2 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountSubstr3(matchA);
    timer.Stop();
    Console.WriteLine("CS3 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrB.CountSubstr3(matchB);
    timer.Stop();
    Console.WriteLine("CS3 and: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrC.CountSubstr3(matchC);
    timer.Stop();
    Console.WriteLine("CS3 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountSubstr4(matchA);
    timer.Stop();
    Console.WriteLine("CS4 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrB.CountSubstr4(matchB);
    timer.Stop();
    Console.WriteLine("CS4 and: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrC.CountSubstr4(matchC);
    timer.Stop();
    Console.WriteLine("CS4 mlw: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountChar(matchA);
    timer.Stop();
    Console.WriteLine("CC1 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountChar2(matchA);
    timer.Stop();
    Console.WriteLine("CC2 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountChar3(matchA);
    timer.Stop();
    Console.WriteLine("CC3 chr: " + timer.Elapsed.TotalMilliseconds + "ms");

    timer.Restart();
    for (int i = 0; i < testSize; ++i)
        testStrA.CountChar4(matchA);
    timer.Stop();
    Console.WriteLine("CC4 chr: " + timer.Elapsed.TotalMilliseconds + "ms");
}


结果:CSX对应CountSubstrX,CCX对应CountCharX。 “ chr”在字符串中搜索“ _”,“ and”在字符串中搜索“ and”,而“ mlw”在字符串中搜索“ muchlongerword”

CS1 chr: 824.123ms
CS1 and: 586.1893ms
CS1 mlw: 486.5414ms
CS2 chr: 127.8941ms
CS2 and: 806.3918ms
CS2 mlw: 497.318ms
CS3 chr: 201.8896ms
CS3 and: 124.0675ms
CS3 mlw: 212.8341ms
CS4 chr: 81.5183ms
CS4 and: 92.0615ms
CS4 mlw: 116.2197ms
CC1 chr: 66.4078ms
CC2 chr: 64.0161ms
CC3 chr: 65.9013ms
CC4 chr: 65.8206ms


最后,我有一个360万个字符的文件。重复了100,000次“ derp adfderdserp dfaerpderp deasderp”。我使用上述方法在文件中搜索“ derp”,结果是上述结果的100倍。

CS1Derp: 1501.3444ms
CS2Derp: 1585.797ms
CS3Derp: 376.0937ms
CS4Derp: 271.1663ms


所以我的第4种方法肯定是赢家,但是实际上,如果360万个字符文件100次仅花了1586毫秒,更糟的是,这一切可以忽略不计。

我还扫描了360万个字符文件中的'd'char 100次CountSubstr和CountChar方法。结果...

CS1  d : 2606.9513ms
CS2  d : 339.7942ms
CS3  d : 960.281ms
CS4  d : 233.3442ms
CC1  d : 302.4122ms
CC2  d : 280.7719ms
CC3  d : 299.1125ms
CC4  d : 292.9365ms


据此,原始的海报方法对于大干草堆中的单个字符的针非常不好。

注意:所有值已更新为“发行版本”输出。我第一次发布此内容时,意外地忘记了建立在Release模式上。我的某些陈述已被修改。

评论


感谢您提供的效果。速度的系数差异为10可能是不考虑linq或其他简洁编写的解决方案,而是采用扩展方法的原因。

– Andreas Reiff
19/12/18在9:27

#19 楼

出现字符串的通用函数:

public int getNumberOfOccurencies(String inputString, String checkString)
{
    if (checkString.Length > inputString.Length || checkString.Equals("")) { return 0; }
    int lengthDifference = inputString.Length - checkString.Length;
    int occurencies = 0;
    for (int i = 0; i < lengthDifference; i++) {
        if (inputString.Substring(i, checkString.Length).Equals(checkString)) { occurencies++; i += checkString.Length - 1; } }
    return occurencies;
}


评论


这将产生大量的临时字符串,并使垃圾回收器非常努力地工作。

– EricLaw
15年6月29日在16:42

#20 楼

string source = "/once/upon/a/time/";
int count = 0, n = 0;
while ((n = source.IndexOf('/', n) + 1) != 0) count++;


Richard Watson答案的一种变体,字符串中出现char的次数越多,速度越快,效率越高。

虽然我必须说,但并没有广泛介绍测试每个场景,通过使用以下方法,我确实看到了非常显着的速度改进:

int count = 0;
for (int n = 0; n < source.Length; n++) if (source[n] == '/') count++;


#21 楼

            var conditionalStatement = conditionSetting.Value;

            //order of replace matters, remove == before =, incase of ===
            conditionalStatement = conditionalStatement.Replace("==", "~").Replace("!=", "~").Replace('=', '~').Replace('!', '~').Replace('>', '~').Replace('<', '~').Replace(">=", "~").Replace("<=", "~");

            var listOfValidConditions = new List<string>() { "!=", "==", ">", "<", ">=", "<=" };

            if (conditionalStatement.Count(x => x == '~') != 1)
            {
                result.InvalidFieldList.Add(new KeyFieldData(batch.DECurrentField, "The IsDoubleKeyCondition does not contain a supported conditional statement. Contact System Administrator."));
                result.Status = ValidatorStatus.Fail;
                return result;
            }


需要执行类似于测试字符串中条件语句的操作。

用单个字符替换了我要查找的内容,并计算了单个字符的实例。

很显然,在此情况下,需要检查所使用的单个字符在字符串中是否不存在,以避免计数错误。

#22 楼

字符串中的字符串:

在“ .. JD JD JD JD etc.等。JDJDJDJDJDJDJDJDJDJD等”中找到“等”。

var strOrigin = " .. JD JD JD JD etc. and etc. JDJDJDJDJDJDJDJD and etc.";
var searchStr = "etc";
int count = (strOrigin.Length - strOrigin.Replace(searchStr, "").Length)/searchStr.Length.


请先检查一下性能,再将其丢弃为笨拙/笨拙...

#23 楼

我最初的想法是:

public static int CountOccurrences(string original, string substring)
{
    if (string.IsNullOrEmpty(substring))
        return 0;
    if (substring.Length == 1)
        return CountOccurrences(original, substring[0]);
    if (string.IsNullOrEmpty(original) ||
        substring.Length > original.Length)
        return 0;
    int substringCount = 0;
    for (int charIndex = 0; charIndex < original.Length; charIndex++)
    {
        for (int subCharIndex = 0, secondaryCharIndex = charIndex; subCharIndex < substring.Length && secondaryCharIndex < original.Length; subCharIndex++, secondaryCharIndex++)
        {
            if (substring[subCharIndex] != original[secondaryCharIndex])
                goto continueOuter;
        }
        if (charIndex + substring.Length > original.Length)
            break;
        charIndex += substring.Length - 1;
        substringCount++;
    continueOuter:
        ;
    }
    return substringCount;
}

public static int CountOccurrences(string original, char @char)
{
    if (string.IsNullOrEmpty(original))
        return 0;
    int substringCount = 0;
    for (int charIndex = 0; charIndex < original.Length; charIndex++)
        if (@char == original[charIndex])
            substringCount++;
    return substringCount;
}


用替换和除草方法在大海捞针中产生的针头产生21+秒,而这大约需要15.2秒。

在添加了将substring.Length - 1添加到charIndex(像它应该的那样)之后,进行编辑,时间为11.6秒。

编辑2:我使用了一个包含26个两个字符的字符串,这里时间更新为相同的示例文本:

大海捞针(OP的版本):7.8秒

机制:4.6秒。

编辑3:添加单个字符的大写字母后,时间为1.2秒。

编辑4:在上下文中:使用了5000万次迭代。

#24 楼

以为我会把扩展方法丢进去(更多信息请参见评论)。我没有做任何正式的基准测试,但是我认为在大多数情况下它必须非常快。

编辑:好的-这个问题让我想知道我们当前实现的性能如何与此处介绍的一些解决方案相提并论。我决定进行一些基准测试,发现我们的解决方案与Richard Watson提供的解决方案的性能非常一致,直到您使用大字符串(100 Kb +),大子字符串(32 Kb + )和许多嵌入式重复(10K +)。到那时,我们的解决方案要慢2到4倍。考虑到这一点以及我们真的很喜欢Richard Watson提出的解决方案的事实,我们相应地重构了我们的解决方案。我只是想将其提供给可能会从中受益的任何人。

我们原始的解决方案:

    /// <summary>
    /// Counts the number of occurrences of the specified substring within
    /// the current string.
    /// </summary>
    /// <param name="s">The current string.</param>
    /// <param name="substring">The substring we are searching for.</param>
    /// <param name="aggressiveSearch">Indicates whether or not the algorithm 
    /// should be aggressive in its search behavior (see Remarks). Default 
    /// behavior is non-aggressive.</param>
    /// <remarks>This algorithm has two search modes - aggressive and 
    /// non-aggressive. When in aggressive search mode (aggressiveSearch = 
    /// true), the algorithm will try to match at every possible starting 
    /// character index within the string. When false, all subsequent 
    /// character indexes within a substring match will not be evaluated. 
    /// For example, if the string was 'abbbc' and we were searching for 
    /// the substring 'bb', then aggressive search would find 2 matches 
    /// with starting indexes of 1 and 2. Non aggressive search would find 
    /// just 1 match with starting index at 1. After the match was made, 
    /// the non aggressive search would attempt to make it's next match 
    /// starting at index 3 instead of 2.</remarks>
    /// <returns>The count of occurrences of the substring within the string.</returns>
    public static int CountOccurrences(this string s, string substring, 
        bool aggressiveSearch = false)
    {
        // if s or substring is null or empty, substring cannot be found in s
        if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring))
            return 0;

        // if the length of substring is greater than the length of s,
        // substring cannot be found in s
        if (substring.Length > s.Length)
            return 0;

        var sChars = s.ToCharArray();
        var substringChars = substring.ToCharArray();
        var count = 0;
        var sCharsIndex = 0;

        // substring cannot start in s beyond following index
        var lastStartIndex = sChars.Length - substringChars.Length;

        while (sCharsIndex <= lastStartIndex)
        {
            if (sChars[sCharsIndex] == substringChars[0])
            {
                // potential match checking
                var match = true;
                var offset = 1;
                while (offset < substringChars.Length)
                {
                    if (sChars[sCharsIndex + offset] != substringChars[offset])
                    {
                        match = false;
                        break;
                    }
                    offset++;
                }
                if (match)
                {
                    count++;
                    // if aggressive, just advance to next char in s, otherwise, 
                    // skip past the match just found in s
                    sCharsIndex += aggressiveSearch ? 1 : substringChars.Length;
                }
                else
                {
                    // no match found, just move to next char in s
                    sCharsIndex++;
                }
            }
            else
            {
                // no match at current index, move along
                sCharsIndex++;
            }
        }

        return count;
    }


这是我们修改后的解决方案:

    /// <summary>
    /// Counts the number of occurrences of the specified substring within
    /// the current string.
    /// </summary>
    /// <param name="s">The current string.</param>
    /// <param name="substring">The substring we are searching for.</param>
    /// <param name="aggressiveSearch">Indicates whether or not the algorithm 
    /// should be aggressive in its search behavior (see Remarks). Default 
    /// behavior is non-aggressive.</param>
    /// <remarks>This algorithm has two search modes - aggressive and 
    /// non-aggressive. When in aggressive search mode (aggressiveSearch = 
    /// true), the algorithm will try to match at every possible starting 
    /// character index within the string. When false, all subsequent 
    /// character indexes within a substring match will not be evaluated. 
    /// For example, if the string was 'abbbc' and we were searching for 
    /// the substring 'bb', then aggressive search would find 2 matches 
    /// with starting indexes of 1 and 2. Non aggressive search would find 
    /// just 1 match with starting index at 1. After the match was made, 
    /// the non aggressive search would attempt to make it's next match 
    /// starting at index 3 instead of 2.</remarks>
    /// <returns>The count of occurrences of the substring within the string.</returns>
    public static int CountOccurrences(this string s, string substring, 
        bool aggressiveSearch = false)
    {
        // if s or substring is null or empty, substring cannot be found in s
        if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(substring))
            return 0;

        // if the length of substring is greater than the length of s,
        // substring cannot be found in s
        if (substring.Length > s.Length)
            return 0;

        int count = 0, n = 0;
        while ((n = s.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
        {
            if (aggressiveSearch)
                n++;
            else
                n += substring.Length;
            count++;
        }

        return count;
    }


#25 楼

string Name = "Very good nice one is very good but is very good nice one this is called the term";
bool valid=true;
int count = 0;
int k=0;
int m = 0;
while (valid)
{
    k = Name.Substring(m,Name.Length-m).IndexOf("good");
    if (k != -1)
    {
        count++;
        m = m + k + 4;
    }
    else
        valid = false;
}
Console.WriteLine(count + " Times accures");


#26 楼

string s = "HOWLYH THIS ACTUALLY WORKSH WOWH";
int count = 0;
for (int i = 0; i < s.Length; i++)
   if (s[i] == 'H') count++;


它只检查字符串中的每个字符,如果该字符是您要搜索的字符,则加一个即可计数。

#27 楼

如果您查看此网页,则会以15种不同的方式来进行测试,包括使用并行循环。

最快的方法似乎是使用单线程的for循环(如果您使用.Net版本, <4.0)或parallel.for循环(如果使用.Net> 4.0并进行了数千次检查)。

假设“ ss”是您的搜索字符串,“ ch”是您的字符数组(如果您有不止是您要查找的一个字符),以下是单线程运行时间最快的代码的基本要点:

for (int x = 0; x < ss.Length; x++)
{
    for (int y = 0; y < ch.Length; y++)
    {
        for (int a = 0; a < ss[x].Length; a++ )
        {
        if (ss[x][a] == ch[y])
            //it's found. DO what you need to here.
        }
    }
}


提供了基准测试源代码也可以运行自己的测试。

#28 楼

str="aaabbbbjjja";
int count = 0;
int size = str.Length;

string[] strarray = new string[size];
for (int i = 0; i < str.Length; i++)
{
    strarray[i] = str.Substring(i, 1);
}
Array.Sort(strarray);
str = "";
for (int i = 0; i < strarray.Length - 1; i++)
{

    if (strarray[i] == strarray[i + 1])
    {

        count++;
    }
    else
    {
        count++;
        str = str + strarray[i] + count;
        count = 0;
    }

}
count++;
str = str + strarray[strarray.Length - 1] + count;


这是用于计算字符出现的次数。对于此示例,输出将为“ a4b4j3”

评论


不是更多的“计数字符串的出现”更多的计数字符-指定Narenda要匹配的字符串的方法怎么样?

– Paul Sullivan
2011-12-09 13:51

int count = 0; string str =“我们有foo和foo,请在此计算foo”;字符串stroccurance =“ foo”; string [] strarray = str.Split(''); Array.Sort(strarray); str =“”; for(int i = 0; i
– Narendra Kumar
2011-12-15 7:10



#29 楼

对于字符串定界符的情况(如主题所述,不适用于char情况):
字符串源=“ @@@ once @@@ upon @@@ a @@@ time @@@”;
int count = source.Split(new [] {“ @@@”},StringSplitOptions.RemoveEmptyEntries).Length-1;
张贴者的原始来源值是(“ / once / upon / a / time / “)自然分隔符是一个字符'/',并且响应确实解释了source.Split(char [])选项,但...

#30 楼

使用System.Linq;

int CountOf =>“ A :: B C :: D” .Split(“ ::”)。Length-1;