c# - एक स्ट्रिंग के भीतर आप एक स्ट्रिंग(वास्तव में एक char) की घटनाओं की गणना कैसे करेंगे?




string (19)

LINQ सभी संग्रहों पर काम करता है, और चूंकि तार केवल वर्णों का संग्रह हैं, इस छोटे से छोटे-लाइनर के बारे में कैसे:

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

सुनिश्चित करें कि आपने using System.Linq; आपकी कोड फ़ाइल के शीर्ष पर, जैसे। .Count उस नामस्थान से एक एक्सटेंशन विधि है।

मैं ऐसा कुछ कर रहा हूं जहां मुझे एहसास हुआ कि मैं गिनना चाहता था कि मैं एक स्ट्रिंग में कितने / मिल सकता था, और फिर उसने मुझे मारा, कि ऐसा करने के कई तरीके थे, लेकिन यह तय नहीं कर सका कि सबसे अच्छा (या सबसे आसान) था।

फिलहाल मैं कुछ इस तरह से जा रहा हूं:

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;

तारों की घटनाओं के लिए एक सामान्य कार्य:

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;
}

मेरे शुरुआती लेते ने मुझे कुछ दिया:

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 जोड़ देगा। तरंग substring.Length - 1 charIndex (जैसे यह चाहिए), यह 11.6 सेकंड पर है।

संपादित करें 2: मैंने एक स्ट्रिंग का उपयोग किया जिसमें 26 दो-वर्ण तार थे, यहां एक ही नमूना ग्रंथों में अपडेट किए गए समय हैं:

एक घास में सुई (ओपी का संस्करण): 7.8 सेकेंड

सुझाया गया तंत्र: 4.6 सेकंड।

संपादित करें 3: एकल वर्ण कोने-केस जोड़ना, यह 1.2 सेकंड तक चला गया।

संपादित करें 4: संदर्भ के लिए: 50 मिलियन पुनरावृत्तियों का उपयोग किया गया था।


मैंने कुछ शोध किया है और पाया है कि ज्यादातर मामलों में रिचर्ड वाटसन का समाधान सबसे तेज़ है। पोस्ट में प्रत्येक समाधान के परिणाम के साथ यह तालिका है (उनको छोड़कर रेगेक्स का उपयोग करें क्योंकि यह "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 वर्ण) के अवसरों की संख्या खोजने के मामले में मूल एल्गोरिदम को प्राथमिकता दी जाती है।

इसके अलावा, मल्टीचार्टर सबस्ट्रिंग के लिए आपको निम्न कोड का उपयोग करना चाहिए ( रिचर्ड वाटसन के समाधान के आधार पर)

int count = 0, n = 0;

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

यदि आप इस वेबपृष्ठ को देखते हैं , तो ऐसा करने के 15 अलग-अलग तरीके समानांतर लूप का उपयोग करके बेंचमार्क किए गए हैं।

सबसे तेज़ तरीका या तो एक थ्रेडेड फॉर-लूप (यदि आपके पास .Net संस्करण <4.0) है या समानांतर है। लूप (यदि हजारों चेक के साथ .NET> 4.0 का उपयोग कर रहे हैं) का उपयोग करना प्रतीत होता है।

मान लें कि "एसएस" आपकी खोज स्ट्रिंग है, "सी" आपका चरित्र सरणी है (यदि आपके पास एक से अधिक char हैं जो आप ढूंढ रहे हैं), यहां कोड का मूल आधार है जिसमें सबसे तेज़ रन टाइम सिंगल थ्रेडेड था:

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.
        }
    }
}

बेंचमार्क स्रोत कोड भी प्रदान किया जाता है ताकि आप अपने स्वयं के परीक्षण चला सकें।


यदि आप पूरे तारों की खोज करने में सक्षम होना चाहते हैं, न कि केवल वर्ण:

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

स्ट्रिंग में प्रत्येक वर्ण के लिए "उस वर्ण से शुरू होने वाली शेष स्ट्रिंग को एक सबस्ट्रिंग के रूप में पढ़ें; इसे लक्ष्य स्ट्रिंग के साथ शुरू होने पर गिनें।"


सी # में, एक अच्छा स्ट्रिंग सबस्ट्रिंग काउंटर यह अप्रत्याशित रूप से मुश्किल साथी है:

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

सोचा था कि मैं अपनी विस्तार विधि को अंगूठी में फेंक दूंगा (अधिक जानकारी के लिए टिप्पणियां देखें)। मैंने कोई औपचारिक बेंच अंकन नहीं किया है, लेकिन मुझे लगता है कि ज्यादातर परिदृश्यों के लिए इसे बहुत तेज होना है।

संपादित करें: ठीक है - तो इस SO सवाल ने मुझे यह सोचने के लिए प्रेरित किया कि हमारे वर्तमान कार्यान्वयन का प्रदर्शन यहां प्रस्तुत कुछ समाधानों के खिलाफ कैसे खड़ा होगा। मैंने थोड़ा बेंच अंकन करने का फैसला किया और पाया कि रिचर्ड वाटसन द्वारा प्रदान किए गए समाधान के प्रदर्शन के साथ हमारा समाधान बहुत अधिक था जब तक कि आप बड़े तारों (100 Kb +), बड़े सबस्ट्रिंग्स (32 Kb + ) और कई एम्बेडेड पुनरावृत्ति (10 के +)। उस समय हमारा समाधान लगभग 2 एक्स से 4 एक्स धीमा था। यह देखते हुए और तथ्य यह है कि हमें वास्तव में रिचर्ड वाटसन द्वारा प्रस्तुत समाधान पसंद है, हमने तदनुसार हमारे समाधान को दोबारा प्रतिक्रिया दी है। मैं बस इसे किसी ऐसे व्यक्ति के लिए उपलब्ध करना चाहता था जो इससे लाभ उठा सके।

हमारा मूल समाधान:

    /// <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;
    }

स्ट्रिंग डेलीमीटर के मामले में (चार मामले के लिए नहीं, जैसा कि विषय कहता है):
स्ट्रिंग स्रोत = "@@@ एक बार @@@ @@@@@@@@@@@@@@@@@@@@ @
int गिनती = स्रोत। स्प्लिट (नया [] {"@@@"}, स्ट्रिंगस्प्लिटऑप्शन। रीमूवइएक्ट्रीइन्ट्रीज़)। लम्बाई - 1;

पोस्टर का मूल स्रोत मान ("/ एक बार / एक / समय /") प्राकृतिक डेलीमीटर एक चार '/' है और प्रतिक्रिया स्रोत को समझाती है। स्प्लिट (char []) विकल्प हालांकि ...


स्ट्रिंग में स्ट्रिंग:

"आदि" में खोजें ".. जेडी जेडी जेडी जेडी आदि आदि। जेडीजेडीजेडीजेडीजेडीजेडीजेडीजेडी और आदि"

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.

इसे किसी को अस्वस्थ / बेकार के रूप में हटाने से पहले प्रदर्शन की जांच करें ...


            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;
            }

एक स्ट्रिंग से परीक्षण सशर्त बयान के समान कुछ करने की आवश्यकता है।

जो मैंने एक चरित्र के साथ खोजा था उसे बदल दिया और एकल चरित्र के उदाहरणों की गिनती की।

स्पष्ट रूप से गलत वर्ण से बचने के लिए ऐसा होने वाला एक भी अक्षर जो स्ट्रिंग में मौजूद नहीं है, उसे जांचने की आवश्यकता होगी।


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

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

चूंकि मूल समाधान, वर्णों के लिए सबसे तेज़ था, मुझे लगता है कि यह तारों के लिए भी होगा। तो मेरा योगदान यहाँ है।

संदर्भ के लिए: मैं लॉग फ़ाइल में 'विफल' और 'सफल' जैसे शब्दों की तलाश में था।

जीआर, बेन


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;
}

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");

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

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

यह हर बार गिनती करेगा जब कार्यक्रम "/ एस" बिल्कुल (केस संवेदनशील) पाता है और इसकी घटनाओं की संख्या परिवर्तनीय "घटनाओं" में संग्रहीत की जाएगी


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

रिचर्ड वाटसन के जवाब पर एक बदलाव, दक्षता में सुधार के साथ थोड़ा तेज़ स्ट्रिंग में चार बार होता है, और कम कोड!

हालांकि मुझे कहना होगा कि, हर परिदृश्य का व्यापक परीक्षण किए बिना, मैंने इसका उपयोग करके एक बहुत ही महत्वपूर्ण गति सुधार देखा:

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

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

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

मेरे कंप्यूटर पर यह 50 मिलियन पुनरावृत्तियों के लिए हर-चरित्र समाधान की तुलना में लगभग 2 सेकंड तेज है।

2013 संशोधन:

स्ट्रिंग को एक char [] में बदलें और उसके माध्यम से फिर से करें। 50 मीटर पुनरावृत्तियों के लिए कुल समय से आगे दो या दो कटौती!

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 सवाल पर आया जो कष्टप्रद रूप से तार [] तकनीक को स्ट्रिंग का उपयोग करता है। मुझे लगता है कि रिवर्सल चाल इस संदर्भ में नई है, हालांकि।

C # में स्ट्रिंग में अलग-अलग वर्णों के माध्यम से पुनरावृत्ति करने का सबसे तेज़ तरीका क्या है?






string