Advertisement
Guest User

Dan Tao

a guest
Dec 30th, 2010
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.07 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6.  
  7. namespace SplitOnLength
  8. {
  9.     enum WordPolicy
  10.     {
  11.         None,
  12.         ThrowIfTooLong,
  13.         CutIfTooLong
  14.     }
  15.  
  16.     static class StringSplitter
  17.     {
  18.         public static IEnumerable<string> SimonsApproach(this string input, int length)
  19.         {
  20.             if (input == null)
  21.                 yield break;
  22.  
  23.             string chunk;
  24.             int current = 0;
  25.             int lastSep = -1;
  26.             for (int i = 0; i < input.Length; i++)
  27.             {
  28.                 if (char.IsSeparator(input[i]))
  29.                 {
  30.                     lastSep = i;
  31.                     continue;
  32.                 }
  33.  
  34.                 if ((i - current) >= length)
  35.                 {
  36.                     if (lastSep < 0) // big first word case
  37.                         continue;
  38.  
  39.                     chunk = input.Substring(current, lastSep - current).Trim();
  40.                     if (chunk.Length > 0)
  41.                         yield return chunk;
  42.  
  43.                     current = lastSep;
  44.                 }
  45.             }
  46.             chunk = input.Substring(current).Trim();
  47.             if (chunk.Length > 0)
  48.                 yield return chunk;
  49.         }
  50.  
  51.         public static IEnumerable<string> JaysOriginalApproach(this string s, int length)
  52.         {
  53.             var pattern = @"^.{0," + length + @"}\W";
  54.             var result = Regex.Match(s, pattern).Groups[0].Value;
  55.  
  56.             if (result == string.Empty)
  57.             {
  58.                 if (s == string.Empty) yield break;
  59.                 result = s.Substring(0, length);
  60.             }
  61.  
  62.             yield return result;
  63.  
  64.             foreach (var subsequent_result in JaysOriginalApproach(s.Substring(result.Length), length))
  65.             {
  66.                 yield return subsequent_result;
  67.             }
  68.         }
  69.  
  70.         public static IEnumerable<string> JaysApproach(this string s, int length)
  71.         {
  72.             return Regex.Split(s, @"(.{0," + length + @"}) ")
  73.                 .Where(x => x != string.Empty);
  74.         }
  75.        
  76.         public static IEnumerable<string> SaeedsOriginalApproach(this string str, int allowedLength)
  77.         {
  78.             var ret1 = str.Split(' ');
  79.             var ret2 = new List<string>();
  80.             ret2.Add("");
  81.             int index = 0;
  82.             foreach (var item in ret1)
  83.             {
  84.                 if (item.Length + 1 + ret2[index].Length <= allowedLength)
  85.                 {
  86.                     ret2[index] += ' ' + item;
  87.                     if (ret2[index].Length >= allowedLength)
  88.                     {
  89.                         ret2.Add("");
  90.                         index++;
  91.                     }
  92.                 }
  93.                 else
  94.                 {
  95.                     ret2.Add(item);
  96.                     index++;
  97.                 }
  98.             }
  99.             return ret2;
  100.         }
  101.  
  102.         public static IEnumerable<string> SaeedsApproach(this string str, int allowedLength)
  103.         {
  104.             var ret1 = str.Split(' ');
  105.             string current = "";
  106.             foreach (var item in ret1)
  107.             {
  108.                 if (item.Length + 1 + current.Length <= allowedLength)
  109.                 {
  110.                     current += ' ' + item;
  111.                     if (current.Length >= allowedLength)
  112.                     {
  113.                         yield return current;
  114.                         current = "";
  115.                     }
  116.                 }
  117.                 else
  118.                 {
  119.                     yield return current;
  120.                     current = "";
  121.                 }
  122.             }
  123.         }
  124.  
  125.         public static IEnumerable<string> SplitOnLength(this string input, int length, WordPolicy wordPolicy)
  126.         {
  127.             int index = 0;
  128.             while (index < input.Length)
  129.             {
  130.                 int stepsBackward = 0;
  131.  
  132.                 if (index + length < input.Length)
  133.                 {
  134.                     if (wordPolicy != WordPolicy.None)
  135.                     {
  136.                         yield return GetBiggestAllowableSubstring(input, index, length, wordPolicy, out stepsBackward);
  137.                     }
  138.                     else
  139.                     {
  140.                         yield return input.Substring(index, length);
  141.                     }
  142.                 }
  143.                 else
  144.                 {
  145.                     yield return input.Substring(index);
  146.                 }
  147.  
  148.                 index += (length - stepsBackward);
  149.             }
  150.         }
  151.  
  152.         static string GetBiggestAllowableSubstring(string input, int index, int length, WordPolicy wordPolicy, out int stepsBackward)
  153.         {
  154.             stepsBackward = 0;
  155.  
  156.             int lastIndex = index + length - 1;
  157.  
  158.             if (!char.IsWhiteSpace(input[lastIndex + 1]))
  159.             {
  160.                 int adjustedLastIndex = input.LastIndexOf(' ', lastIndex, length);
  161.                 stepsBackward = lastIndex - adjustedLastIndex;
  162.                 lastIndex = adjustedLastIndex;
  163.             }
  164.  
  165.             if (lastIndex == -1)
  166.             {
  167.                 if (wordPolicy == WordPolicy.ThrowIfTooLong)
  168.                 {
  169.                     throw new ArgumentOutOfRangeException("The input string contains at least one word greater in length than the specified length.");
  170.                 }
  171.                 else
  172.                 {
  173.                     stepsBackward = 0;
  174.                     lastIndex = index + length - 1;
  175.                 }
  176.             }
  177.  
  178.             return input.Substring(index, lastIndex - index + 1);
  179.         }
  180.     }
  181.  
  182.     class Program
  183.     {
  184.         static void Main(string[] args)
  185.         {
  186.             string s = "This is a sample block of text that I would pass through the string splitter.";
  187.  
  188.             PrintResultsOfSplitMethod("Dan", s, 10, (str, len) => str.SplitOnLength(len, WordPolicy.CutIfTooLong));
  189.             PrintResultsOfSplitMethod("Jay", s, 10, StringSplitter.JaysApproach);
  190.             PrintResultsOfSplitMethod("Jay (original)", s, 10, StringSplitter.JaysOriginalApproach);
  191.             PrintResultsOfSplitMethod("Saeed", s, 10, StringSplitter.SaeedsApproach);
  192.             PrintResultsOfSplitMethod("Saeed (original)", s, 10, StringSplitter.SaeedsOriginalApproach);
  193.             PrintResultsOfSplitMethod("Simon", s, 10, StringSplitter.SimonsApproach);
  194.  
  195.             Console.WriteLine("Finished. Press Enter to continue.");
  196.             Console.ReadLine();
  197.  
  198.             // This is the entire text of Kafka's 'In the Penal Colony',
  199.             // as a sample input of significant length.
  200.             string longInput = SplitOnLength.Properties.Resources.InThePenalColony;
  201.  
  202.             // This is an excerpt of the text of the OP's question,
  203.             // as a sample input of small-medium length.
  204.             string shortInput = SplitOnLength.Properties.Resources.QuestionText;
  205.  
  206.             bool keepGoing;
  207.  
  208.             do
  209.             {
  210.                 try
  211.                 {
  212.                     Console.Write("Enter a split size: ");
  213.                     int length = int.Parse(Console.ReadLine());
  214.  
  215.                     Console.WriteLine();
  216.                     Console.WriteLine("Results from longer input:");
  217.                     foreach (var result in GetResultsForInputAndLength(longInput, length).OrderBy(x => x.Value))
  218.                     {
  219.                         Console.WriteLine("{0}: {1} ms", result.Key, result.Value.TotalMilliseconds);
  220.                     }
  221.  
  222.                     Console.WriteLine();
  223.                     Console.WriteLine("Results from shorter input:");
  224.                     foreach (var result in GetResultsForInputAndLength(shortInput, length).OrderBy(x => x.Value))
  225.                     {
  226.                         Console.WriteLine("{0}: {1} ms", result.Key, result.Value.TotalMilliseconds);
  227.                     }
  228.                 }
  229.                 catch (Exception ex)
  230.                 {
  231.                     Console.WriteLine(ex.Message);
  232.                 }
  233.                 finally
  234.                 {
  235.                     Console.WriteLine();
  236.                     Console.Write("Go again? ");
  237.                     keepGoing = Console.ReadLine().StartsWith("Y", StringComparison.OrdinalIgnoreCase);
  238.                     Console.WriteLine();
  239.                 }
  240.             }
  241.             while (keepGoing);
  242.         }
  243.  
  244.         static void PrintResultsOfSplitMethod(string name, string input, int length, Func<string, int, IEnumerable<string>> splitter)
  245.         {
  246.             Console.WriteLine("Testing {0}'s method:", name);
  247.             IEnumerable<string> split = splitter(input, length);
  248.             foreach (string s in split)
  249.             {
  250.                 Console.WriteLine(s);
  251.             }
  252.  
  253.             Console.WriteLine();
  254.         }
  255.  
  256.         static IDictionary<string, TimeSpan> GetResultsForInputAndLength(string input, int length)
  257.         {
  258.             var results = new Dictionary<string, TimeSpan>
  259.             {
  260.                 { "Dan", TestSplitMethod(input, length, (str, len) => str.SplitOnLength(len, WordPolicy.CutIfTooLong)) },
  261.                 { "Saeed", TestSplitMethod(input, length, StringSplitter.SaeedsOriginalApproach) },
  262.                 { "Saeed (original)", TestSplitMethod(input, length, StringSplitter.SaeedsOriginalApproach) },
  263.                 { "Jay", TestSplitMethod(input, length, StringSplitter.JaysApproach) },
  264.                 { "Simon", TestSplitMethod(input, length, StringSplitter.SimonsApproach) }
  265.             };
  266.  
  267.             return results;
  268.         }
  269.  
  270.         static TimeSpan TestSplitMethod(string input, int length, Func<string, int, IEnumerable<string>> splitter)
  271.         {
  272.             // Ensure results aren't thrown off by garbage collections affecting
  273.             // certain runs more or less harshly than others.
  274.             GC.Collect();
  275.  
  276.             Stopwatch stopwatch = Stopwatch.StartNew();
  277.  
  278.             IEnumerable<string> split = splitter(input, length);
  279.             foreach (string s in split)
  280.             { }
  281.  
  282.             stopwatch.Stop();
  283.  
  284.             return stopwatch.Elapsed;
  285.         }
  286.     }
  287. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement