2011-06-20 18 views
6

का उपयोग करके बाइट सूची/सरणी में अवसरों की गणना करें, मैं किसी अन्य बाइट अनुक्रमों में बाइट अनुक्रमों की हर बार गिनती प्राप्त करने की कोशिश कर रहा हूं। हालांकि यह बाइट्स का फिर से उपयोग नहीं कर सकता है अगर यह पहले से ही गिना जाता है। स्ट्रिंग दिया उदाहरण के लिए
k.k.k.k.k.k. के मान लें बाइट क्रम था k.k यह तो बजाय केवल 3 घटनाओं 5 मिलेगा क्योंकि वे की तरह खराब हो गई होगी: [k.k].[k.k].[k.k]. और नहीं [k.[k].[k].[k].[k].k] जहां वे गोद से अधिक और अनिवार्य रूप से सिर्फ सही करने के लिए 2 बदलाव चाहते ।बाइट सूची/सरणी

आदर्श रूप से विचार यह है कि एक संपीड़न शब्दकोश या रन टाइम एन्कोडिंग कैसा दिख सकता है। तो लक्ष्य

k.k.k.k.k.k. केवल 2 भागों तक नीचे जाना होगा, क्योंकि (के.के.के.) आपके पास सबसे बड़ा और सबसे अच्छा प्रतीक है।

यहाँ स्रोत है अब तक: 011010110010111001101011001011100110101100101110011010110010111001101011001011100110101100101110 मैं इसे से कैसे इसे छोटा करने की उम्मीद कर रहा हूँ:

using System; 
using System.Collections.Generic; 
using System.Collections; 
using System.Linq; 
using System.Text; 
using System.IO; 


    static class Compression 
    { 
     static int Main(string[] args) 
     { 

      List<byte> bytes = File.ReadAllBytes("ok.txt").ToList(); 
      List<List<int>> list = new List<List<int>>(); 

      // Starting Numbers of bytes - This can be changed manually. 
      int StartingNumBytes = bytes.Count; 
      for (int i = StartingNumBytes; i > 0; i--) 
      { 
       Console.WriteLine("i: " + i); 

       for (int ii = 0; ii < bytes.Count - i; ii++) 
       { 
        Console.WriteLine("ii: " + i); 
        // New pattern comes with refresh data. 
        List<byte> pattern = new List<byte>(); 

        for (int iii = 0; iii < i; iii++) 
        { 
         pattern.Add(bytes[ii + iii]); 
        } 



        DisplayBinary(bytes, "red"); 
        DisplayBinary(pattern, "green"); 

        int matches = 0; 
        // foreach (var position in bytes.ToArray().Locate(pattern.ToArray())) 
        for (int position = 0; position < bytes.Count; position++) { 
         if (pattern.Count > (bytes.Count - position)) 
         { 
          continue; 
         } 


         for (int iiii = 0; iiii < pattern.Count; iiii++) 
         { 
          if (bytes[position + iiii] != pattern[iiii]) 
          { 
           //Have to use goto because C# doesn't support continue <level> 
           goto outer; 
          } 

         } 

         // If it made it this far, it has found a match. 
         matches++; 
         Console.WriteLine("Matches: " + matches + " Orig Count: " + bytes.Count + " POS: " + position); 
         if (matches > 1) 
         { 
          int numBytesToRemove = pattern.Count; 
          for (int ra = 0; ra < numBytesToRemove; ra++) 
          { 
           // Remove it at the position it was found at, once it 
           // deletes the first one, the list will shift left and you'll need to be here again. 
           bytes.RemoveAt(position); 
          } 
          DisplayBinary(bytes, "red"); 
          Console.WriteLine(pattern.Count + " Bytes removed."); 

          // Since you deleted some bytes, set the position less because you will need to redo the pos. 
          position = position - 1; 
         } 


         outer: 
          continue; 
        } 

        List<int> sublist = new List<int>(); 
        sublist.Add(matches); 
        sublist.Add(pattern.Count); 
        // Some sort of calculation to determine how good the symbol was 
        sublist.Add(bytes.Count-((matches * pattern.Count)-matches)); 
        list.Add(sublist); 

       } 

      } 



      Display(list); 
      Console.Read(); 
      return 0; 
     } 


     static void DisplayBinary(List<byte> bytes, string color="white") 
     { 
      switch(color){ 
       case "green": 
        Console.ForegroundColor = ConsoleColor.Green; 
        break; 
       case "red": 
        Console.ForegroundColor = ConsoleColor.Red; 
        break; 
       default: 
        break; 
      } 


      for (int i=0; i<bytes.Count; i++) 
      { 
       if (i % 8 ==0) 
        Console.WriteLine(); 
       Console.Write(GetIntBinaryString(bytes[i]) + " "); 
      } 
      Console.WriteLine(); 
      Console.ResetColor(); 
     } 
     static string GetIntBinaryString(int n) 
     { 
      char[] b = new char[8]; 
      int pos = 7; 
      int i = 0; 

      while (i < 8) 
      { 
       if ((n & (1 << i)) != 0) 
       { 
        b[pos] = '1'; 
       } 
       else 
       { 
        b[pos] = '0'; 
       } 
       pos--; 
       i++; 
      } 
      //return new string(b).TrimStart('0'); 
      return new string(b); 
     } 

     static void Display(List<List<int>> list) 
     { 
      // 
      // Display everything in the List. 
      // 
      Console.WriteLine("Elements:"); 
      foreach (var sublist in list) 
      { 
       foreach (var value in sublist) 
       { 
        Console.Write("{0,4}", value); 

       } 
       Console.WriteLine(); 
      } 

      // 
      // Display total count. 
      // 
      int count = 0; 
      foreach (var sublist in list) 
      { 
       count += sublist.Count; 
      } 
      Console.WriteLine("Count:"); 
      Console.WriteLine(count); 
     } 

     static public int SearchBytePattern(byte[] pattern, byte[] bytes) 
     { 
      int matches = 0; 
      // precomputing this shaves some seconds from the loop execution 
      int maxloop = bytes.Length - pattern.Length; 
      for (int i = 0; i < maxloop; i++) 
      { 
       if (pattern[0] == bytes[i]) 
       { 
        bool ismatch = true; 
        for (int j = 1; j < pattern.Length; j++) 
        { 
         if (bytes[i + j] != pattern[j]) 
         { 
          ismatch = false; 
          break; 
         } 
        } 
        if (ismatch) 
        { 
         matches++; 
         i += pattern.Length - 1; 
        } 
       } 
      } 
      return matches; 
     } 
    } 

फ़ाइल के गैर द्विआधारी प्राप्त करने के लिए किया जाना चाहिए पद का संदर्भ लें, यहाँ बाइनरी डेटा है शुरू कर दिया है।

+0

संभावित रूप से संदर्भ कॉलिंग प्रासंगिक है। जैसे अगर हम जानते हैं कि हम एक बाइट सरणी में कई पैटर्न खोज रहे हैं और प्रत्येक पैटर्न teh समान लंबाई है तो यह शायद खोज सरणी में प्रत्येक possibel उप-स्ट्रिंग के लिए precalc हैश कोड को समझ में आता है - तो आप हैश कोड की तुलना कर सकते हैं (उदाहरण के लिए आमतौर पर एक एकल int32) अनुक्रम में प्रत्येक बाइट के बजाय। लेकिन यदि कोड कोड हैं (हैश कोड आपको बताते हैं कि अनुक्रम निश्चित रूप से मेल नहीं खाता है या अन्यथा/शायद/मिलान हो) तो आपको हर बाइट का परीक्षण करना होगा – redcalx

+0

आप यहां एक नजर डाल सकते हैं: http://stackoverflow.com/प्रश्न/283456/बाइट-सर-पैटर्न-सर्च यह आप जो कुछ खोज रहे हैं उसे कवर करता है। – Variant

उत्तर

5
private static int CountOccurences(byte[] target, byte[] pattern) 
{ 
    var targetString = BitConverter.ToString(target); 
    var patternString = BitConverter.ToString(pattern); 
    return new Regex(patternString).Matches(targetString).Count; 
} 
+0

+1 अच्छा और सरल, 'बाइट [] लक्ष्य = नया बाइट [] {1, 2, 3, 2, 3, 1, 2, 3} के साथ परीक्षण किया गया; बाइट [] पैटर्न = नया बाइट [] {2, 3}; ' – shelleybutterfly

+0

दिलचस्प लेकिन ध्यान दें कि यह एक बेहद अक्षम दृष्टिकोण है - बिंदु बड़ी मात्रा में डेटा प्रोसेसिंग और/या सख्त आवश्यकताओं के साथ लाइव सर्वर वातावरण पर चलने के लिए प्रासंगिक है rountrip समय और throughput पर। – redcalx

1

बिना किसी रेगेक्स के त्वरित और गंदे। हालांकि मुझे यकीन नहीं है कि क्या यह प्रश्न के इरादे का जवाब देता है, यह अपेक्षाकृत तेज़ होना चाहिए। मुझे लगता है कि मुझे यकीन है कि सापेक्ष गति के लिए देखने के लिए regex के खिलाफ कुछ समय परीक्षण चलाने के लिए जा रहा हूँ:

private int CountOccurrences(string TestString, string TestPattern) 
    { 
     int PatternCount = 0; 
     int SearchIndex = 0; 

     if (TestPattern.Length == 0) 
      throw new ApplicationException("CountOccurrences: Unable to process because TestPattern has zero length."); 

     if (TestString.Length == 0) 
      return 0; 

     do 
     { 
      SearchIndex = TestString.IndexOf(TestPattern, SearchIndex); 

      if (SearchIndex >= 0) 
      { 
       ++PatternCount; 
       SearchIndex += TestPattern.Length; 
      } 
     } 
     while ((SearchIndex >= 0) && (SearchIndex < TestString.Length)); 

     return PatternCount; 
    } 

    private void btnTest_Click(object sender, EventArgs e) 
    { 
     string TestString1 = "k.k.k.k.k.k.k.k.k.k.k.k"; 
     string TestPattern1 = "k.k"; 

     System.Console.WriteLine(CountOccurrences(TestString1, TestPattern1).ToString()); // outputs 6 
     System.Console.WriteLine(CountOccurrences(TestString1 + ".k", TestPattern1).ToString()); // still 6 
     System.Console.WriteLine(CountOccurrences(TestString1, TestPattern1 + ".").ToString()); // only 5 
    } 
+0

भी, आपकी पोस्ट ने मुझे हफमैन एन्कोडिंग के बारे में सोचने में मदद की, मैं हमेशा के साथ खेलने के लिए मजेदार था ... यदि आप रुचि रखते हैं तो यहां एक अच्छा परिचय है: http://www.cs.auckland.ac.nz/~jmor159 /PLDS210/huffman.html – shelleybutterfly

+0

आपके प्रश्न के कोड के साथ आगे की तुलना में मैं देखता हूं कि वास्तव में यह आवश्यक नहीं है क्योंकि आप बाइनरी कर रहे हैं ... मैं बस इतना कहने के लिए कोड छोड़ दूंगा: मैं कोशिश करने के लिए लुभाना चाहूंगा कुछ ऐसा करना जो बाइट [] एस में गुजर रहा है और फिर स्ट्रिंग और खोज करने के लिए कास्टिंग कर रहा है"स्ट्रिंग टेस्टस्ट्रिंग = System.Text.Encoding.ASCII.GetString (टेस्टबाइट्स);" सिवाय इसके कि कुछ संस्कृतियों के लिए कुछ मिलान नियम हैं जो इस काम को सही तरीके से रोक देंगे। आह अच्छा :) – shelleybutterfly

2

इस समाधान के साथ आप अलग-अलग अनुक्रमित जिनका मिलान (जबकि गणना) के लिए उपयोग होगा या आप कह सकते हैं Count() परिणाम पर देखने के लिए कितने मैचों वहाँ थे:

public static IEnumerable<int> Find<T>(T[] pattern, T[] sequence, bool overlap) 
{ 
    int i = 0; 
    while (i < sequence.Length - pattern.Length + 1) 
    { 
     if (pattern.SequenceEqual(sequence.Skip(i).Take(pattern.Length))) 
     { 
      yield return i; 
      i += overlap ? 1 : pattern.Length; 
     } 
     else 
     { 
      i++; 
     } 
    } 
}

overlap: false साथ कॉल यह आपकी समस्या या overlap: true हल करने के लिए ओवरलैप मेल देखने के लिए

मैं एसी है (यदि आप रुचि रखते हैं।) थोड़ा अलग एपीआई (बेहतर प्रदर्शन के साथ) के साथ अन्य तरीकों का खुलासा here, जिसमें बाइट्स की धाराओं पर सीधे काम करने वाला एक भी शामिल है।