- Main Page
- Classes
- Files

- File List

# C:/Users/Andreas Schiffler/Desktop/SVN/NewGamePhysics/NewGamePhysics/Utilities/Scanf.cs

    00001 ﻿//-----------------------------------------------------------------------------
    00002 // Scanf.cs
    00003 // (A. Schiffler, 2009)
    00004 //-----------------------------------------------------------------------------
    00005
    00006 namespace NewGamePhysics.Utilities
    00007 {
    00008     using System;
    00009     using System.Collections;
    00010     using System.Collections.Generic;
    00011     using System.Globalization;
    00012     using System.Linq;
    00013     using System.Text;
    00014     using System.Text.RegularExpressions;
    00015
    00019     internal enum ParseType
    00020     {
    00021         Null,
    00022         Int16,
    00023         UInt16,
    00024         UInt16Oct,
    00025         UInt16Hex,
    00026         Int32,
    00027         UInt32,
    00028         UInt32Oct,
    00029         UInt32Hex,
    00030         Int64,
    00031         UInt64,
    00032         UInt64Oct,
    00033         UInt64Hex,
    00034         Single,
    00035         String,
    00036         Double,
    00037         Char
    00038     }
    00039
    00044     public class Scanf
    00045     {
    00049         private const string integerPattern = @"[-+]?[0-9]+";
    00050
    00054         private const string octalIntegerPattern = @"[0-7]+";
    00055
    00059         private const string hexadecimalIntegerPattern = @"[0-9a-fA-F]+";
    00060
    00064         private const string floatingPointPattern = @"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?";
    00065
    00069         private const string stringPattern = @"[\w\d\S]+";
    00070
    00074         private const string characterPattern = @"[\w\S]{1}";
    00075
    00079         private static char[] seperator = { '_' };
    00080
    00084         protected readonly Hashtable patterns;
    00085
    00089         protected readonly Hashtable types;
    00090
    00095         public static bool EnableTrace = false;
    00096
    00100         private MatchEvaluator matchEvaluator;
    00101
    00106         private int typeCount;
    00107
    00112         private string lastFormat;
    00113
    00117         private Regex conversionRegex;
    00118
    00123         public Scanf()
    00124         {
    00125             // New format-to-regexp pattern table
    00126             patterns = new Hashtable();
    00127
    00128             // base-types
    00129             patterns.Add("%d", integerPattern);
    00130             patterns.Add("%i", integerPattern);
    00131             patterns.Add("%o", octalIntegerPattern);
    00132             patterns.Add("%u", integerPattern);
    00133             patterns.Add("%x", hexadecimalIntegerPattern);
    00134             patterns.Add("%X", hexadecimalIntegerPattern);
    00135             patterns.Add("%f", floatingPointPattern);
    00136             patterns.Add("%g", floatingPointPattern);
    00137             patterns.Add("%G", floatingPointPattern);
    00138             patterns.Add("%s", stringPattern);
    00139             patterns.Add("%c", characterPattern);
    00140
    00141             // long-types
    00142             patterns.Add("%lf", floatingPointPattern);
    00143             patterns.Add("%lg", floatingPointPattern);
    00144             patterns.Add("%lG", floatingPointPattern);
    00145             patterns.Add("%ld", integerPattern);
    00146             patterns.Add("%li", integerPattern);
    00147             patterns.Add("%lo", octalIntegerPattern);
    00148             patterns.Add("%lu", integerPattern);
    00149             patterns.Add("%lx", hexadecimalIntegerPattern);
    00150             patterns.Add("%lX", hexadecimalIntegerPattern);
    00151
    00152             // short-types
    00153             patterns.Add("%hd", integerPattern);
    00154             patterns.Add("%hi", integerPattern);
    00155             patterns.Add("%ho", octalIntegerPattern);
    00156             patterns.Add("%hu", integerPattern);
    00157             patterns.Add("%hx", hexadecimalIntegerPattern);
    00158             patterns.Add("%hX", hexadecimalIntegerPattern);
    00159
    00160             // Skips
    00161             patterns.Add(@"%\*d", integerPattern);
    00162             patterns.Add(@"%\*i", integerPattern);
    00163             patterns.Add(@"%\*o", octalIntegerPattern);
    00164             patterns.Add(@"%\*u", integerPattern);
    00165             patterns.Add(@"%\*x", hexadecimalIntegerPattern);
    00166             patterns.Add(@"%\*X", hexadecimalIntegerPattern);
    00167             patterns.Add(@"%\*f", floatingPointPattern);
    00168             patterns.Add(@"%\*g", floatingPointPattern);
    00169             patterns.Add(@"%\*G", floatingPointPattern);
    00170             patterns.Add(@"%\*s", stringPattern);
    00171             patterns.Add(@"%\*c", characterPattern);
    00172
    00173             patterns.Add(@"%\*lf", floatingPointPattern);
    00174             patterns.Add(@"%\*lg", floatingPointPattern);
    00175             patterns.Add(@"%\*lG", floatingPointPattern);
    00176             patterns.Add(@"%\*ld", integerPattern);
    00177             patterns.Add(@"%\*li", integerPattern);
    00178             patterns.Add(@"%\*lo", octalIntegerPattern);
    00179             patterns.Add(@"%\*lu", integerPattern);
    00180             patterns.Add(@"%\*lx", hexadecimalIntegerPattern);
    00181             patterns.Add(@"%\*lX", hexadecimalIntegerPattern);
    00182
    00183             patterns.Add(@"%\*hd", integerPattern);
    00184             patterns.Add(@"%\*hi", integerPattern);
    00185             patterns.Add(@"%\*ho", octalIntegerPattern);
    00186             patterns.Add(@"%\*hu", integerPattern);
    00187             patterns.Add(@"%\*hx", hexadecimalIntegerPattern);
    00188             patterns.Add(@"%\*hX", hexadecimalIntegerPattern);
    00189
    00190             // New format-to-parse type table
    00191             types = new Hashtable();
    00192
    00193             types.Add("%d", ParseType.Int32);
    00194             types.Add("%i", ParseType.Int32);
    00195             types.Add("%o", ParseType.UInt32Oct);
    00196             types.Add("%u", ParseType.UInt32);
    00197             types.Add("%x", ParseType.UInt32Hex);
    00198             types.Add("%X", ParseType.UInt32Hex);
    00199             types.Add("%f", ParseType.Single);
    00200             types.Add("%g", ParseType.Single);
    00201             types.Add("%G", ParseType.Single);
    00202             types.Add("%s", ParseType.String);
    00203             types.Add("%c", ParseType.Char);
    00204
    00205             types.Add("%lf", ParseType.Double);
    00206             types.Add("%lg", ParseType.Double);
    00207             types.Add("%lG", ParseType.Double);
    00208             types.Add("%ld", ParseType.Int64);
    00209             types.Add("%li", ParseType.Int64);
    00210             types.Add("%lo", ParseType.UInt64Oct);
    00211             types.Add("%lu", ParseType.UInt64);
    00212             types.Add("%lx", ParseType.UInt64Hex);
    00213             types.Add("%lX", ParseType.UInt64Hex);
    00214
    00215             types.Add("%hd", ParseType.Int16);
    00216             types.Add("%hi", ParseType.Int16);
    00217             types.Add("%ho", ParseType.UInt16Oct);
    00218             types.Add("%hu", ParseType.UInt16);
    00219             types.Add("%hx", ParseType.UInt16Hex);
    00220             types.Add("%hX", ParseType.UInt16Hex);
    00221
    00222             // New match evaluator
    00223             matchEvaluator = new MatchEvaluator(ReplaceFormatCode);
    00224         }
    00225
    00241         public object[] Scan(string text, string format)
    00242         {
    00243             // Check if we need to update our regular expression for the format
    00244             if ((String.IsNullOrEmpty(lastFormat)) ||
    00245                 (lastFormat != format))
    00246             {
    00247                 // Convert format string into pattern
    00248                 string formatPattern = format;
    00249
    00250                 // Multiple whitespaces reduce to single whitespace match
    00251                 formatPattern = Regex.Replace(formatPattern, @"\s+", @"\s+");
    00252
    00253                 // Type names are individualized with a counter
    00254                 // The count is updated inside the match evaluator.
    00255                 typeCount = 0;
    00256
    00257                 // Maybe rebuild format pattern
    00258                 foreach (string formatCode in patterns.Keys)
    00259                 {
    00260                     formatPattern = Regex.Replace(
    00261                         formatPattern,
    00262                         formatCode,
    00263                         matchEvaluator);
    00264                 }
    00265                 Trace("scanf_trace: format_pattern: ", formatPattern);
    00266
    00267                 // New regular expression for format
    00268                 conversionRegex = new Regex(formatPattern);
    00269
    00270                 // Cache format for reuse tracking
    00271                 lastFormat = format;
    00272             }
    00273
    00274             // Get the array of group names
    00275             string[] groupNames = conversionRegex.GetGroupNames();
    00276
    00277             // Initalize return array
    00278             List<object> targets = new List<object>();
    00279
    00280             if (groupNames.Length > 0)
    00281             {
    00282                 // Match pattern
    00283                 MatchCollection matchCollection = conversionRegex.Matches(text);
    00284                 foreach (Match match in matchCollection)
    00285                 {
    00286                     if (match.Success)
    00287                     {
    00288                         foreach (string groupName in groupNames)
    00289                         {
    00290                             if (groupName.Contains(seperator[0]))
    00291                             {
    00292                                 // Part until "_" is the type
    00293                                 string typeName = groupName.Remove(groupName.LastIndexOfAny(seperator));
    00294                                 ParseType parseType = (ParseType)Enum.Parse(typeof(ParseType), typeName);
    00295
    00296                                 // Get the value to convert
    00297                                 string valueText = match.Groups[groupName].Value;
    00298
    00299                                 // Try to parse string based on value
    00300                                 object target = null;
    00301                                 try
    00302                                 {
    00303                                     target = Parse(parseType, valueText);
    00304                                 }
    00305                                 catch (Exception e)
    00306                                 {
    00307                                     Trace("scanf_trace: exception:", e.ToString());
    00308                                 }
    00309                                 finally
    00310                                 {
    00311                                     targets.Add(target);
    00312                                 }
    00313
    00314                                 // Terminate early if we have the number of types
    00315                                 // found in the earlier scan
    00316                                 if (targets.Count == typeCount)
    00317                                 {
    00318                                     return targets.ToArray();
    00319                                 }
    00320                             }
    00321                         }
    00322                     }
    00323                 }
    00324             }
    00325
    00326             // Return what we've got
    00327             return targets.ToArray();
    00328         }
    00329
    00335         private string ReplaceFormatCode(Match m)
    00336         {
    00337             string groupName;
    00338
    00339             // Update the group index
    00340             typeCount++;
    00341
    00342             // Determine the group name
    00343             if (types.ContainsKey(m.Value))
    00344             {
    00345                 groupName = types[m.Value].ToString();
    00346             }
    00347             else
    00348             {
    00349                 // Skip pattern
    00350                 groupName = "Null";
    00351             }
    00352
    00353             // Assemble the return string
    00354             StringBuilder sb = new StringBuilder();
    00355             sb.Append("(?<");
    00356             sb.Append(groupName);
    00357             sb.Append(seperator[0]);
    00358             sb.Append(typeCount);
    00359             sb.Append(">");
    00360             sb.Append(patterns[m.Value]);
    00361             sb.Append(")");
    00362
    00363             return sb.ToString();
    00364         }
    00365
    00373         private object Parse(ParseType parseType, string text)
    00374         {
    00375             switch (parseType)
    00376             {
    00377                 case ParseType.Null:
    00378                     return null;
    00379                 case ParseType.String:
    00380                     return text;
    00381                 case ParseType.Int16:
    00382                     return Int16.Parse(text, CultureInfo.InvariantCulture);
    00383                 case ParseType.UInt16:
    00384                     return UInt16.Parse(text, CultureInfo.InvariantCulture);
    00385                 case ParseType.UInt16Hex:
    00386                     return UInt16.Parse(text, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
    00387                 case ParseType.UInt16Oct:
    00388                     return Convert.ToUInt16(text, 8);
    00389                 case ParseType.Int32:
    00390                     return Int32.Parse(text, CultureInfo.InvariantCulture);
    00391                 case ParseType.UInt32:
    00392                     return UInt32.Parse(text, CultureInfo.InvariantCulture);
    00393                 case ParseType.UInt32Hex:
    00394                     return UInt32.Parse(text, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
    00395                 case ParseType.UInt32Oct:
    00396                     return Convert.ToUInt32(text, 8);
    00397                 case ParseType.Int64:
    00398                     return Int64.Parse(text, CultureInfo.InvariantCulture);
    00399                 case ParseType.UInt64:
    00400                     return UInt64.Parse(text, CultureInfo.InvariantCulture);
    00401                 case ParseType.UInt64Hex:
    00402                     return UInt64.Parse(text, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
    00403                 case ParseType.UInt64Oct:
    00404                     return Convert.ToUInt64(text, 8);
    00405                 case ParseType.Single:
    00406                     return Single.Parse(text, CultureInfo.InvariantCulture);
    00407                 case ParseType.Double:
    00408                     return Double.Parse(text, CultureInfo.InvariantCulture);
    00409                 case ParseType.Char:
    00410                     return Char.Parse(text);
    00411             }
    00412
    00413             return null;
    00414         }
    00415
    00420         private static void Trace(string label, string message)
    00421         {
    00422             if (EnableTrace)
    00423             {
    00424                 System.Console.Write(label);
    00425                 System.Console.Write(": ");
    00426                 System.Console.WriteLine(message);
    00427             }
    00428         }
    00429     }
    00430 }