Last active
September 24, 2017 18:50
-
-
Save avalko/0d7a75a59a57c8bd88108bd8d0f8f04d to your computer and use it in GitHub Desktop.
Scanf (analog) writen in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
namespace MonitoringAgent | |
{ | |
class Scanf | |
{ | |
private static readonly string _shortsRegex; | |
private static IReadOnlyDictionary<string, Type> _shorts = new Dictionary<string, Type> | |
{ | |
["s"] = (typeof(string)), | |
["i"] = (typeof(int)), | |
["d"] = (typeof(double)), | |
}; | |
private static IReadOnlyDictionary<Type, string> _patterns = new Dictionary<Type, string> | |
{ | |
[(typeof(string))] = @"[\w\d\S]+", | |
[(typeof(int))] = @"[-]?[0-9]+", | |
[(typeof(double))] = @"[-]?[0-9]*[.]*[0-9]+", | |
}; | |
private IReadOnlyList<Type> _types; | |
private Regex _regex; | |
static Scanf() | |
{ | |
_shortsRegex = string.Join('|', _shorts.ToList().Select(pair => pair.Key)); | |
} | |
private Scanf(Regex regex, IReadOnlyList<Type> types) | |
{ | |
if (regex == null) | |
throw new ArgumentNullException(nameof(regex)); | |
else if (types == null) | |
throw new ArgumentNullException(nameof(types)); | |
_regex = regex; | |
_types = types; | |
} | |
public static Scanf Create(string pattern) | |
{ | |
List<Type> types = new List<Type>(); | |
pattern = Regex.Replace(pattern, $@"\%({_shortsRegex})", (m) => | |
{ | |
var type = _shorts[m.Groups[1].Value]; | |
types.Add(type); | |
return "(" + _patterns[type] + ")"; | |
}); | |
pattern = pattern.RemoveMultipleSpaces().Replace(" ", @"\s+"); | |
return new Scanf(new Regex(pattern, RegexOptions.Compiled), types); | |
} | |
public void Matches(string input, object[] array) | |
{ | |
if (array == null) | |
throw new ArgumentNullException(nameof(array)); | |
var match = _regex.Match(input); | |
int count = match.Groups.Count; | |
int argumentsCount = count - 1; | |
if (array.Length < argumentsCount) | |
throw new ArgumentException($"The array ({nameof(array)}) must contain at least {argumentsCount} elements!"); | |
else if (_types.Count < argumentsCount) | |
throw new ScanfPatternCountException(_types.Count, argumentsCount); | |
for (int i = 0; i < argumentsCount; i++) | |
{ | |
var group = match.Groups[i + 1]; | |
array[i] = Convert.ChangeType(group.Value, _types[i]); | |
} | |
} | |
public object[] Matches(string input) | |
{ | |
var match = _regex.Match(input); | |
int count = match.Groups.Count; | |
int argumentsCount = count - 1; | |
if (_types.Count < argumentsCount) | |
throw new ScanfPatternCountException(_types.Count, argumentsCount); | |
object[] array = new object[argumentsCount]; | |
for (int i = 0; i < argumentsCount; i++) | |
{ | |
var group = match.Groups[i + 1]; | |
array[i] = Convert.ChangeType(group.Value, _types[i]); | |
} | |
return array; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
namespace MonitoringAgent | |
{ | |
class ScanfPatternCountException : Exception | |
{ | |
public ScanfPatternCountException(int patternCount, int argumentsCount) | |
: base($"The pattern contains fewer ({patternCount}) arguments than expected ({argumentsCount}).\n" + | |
"It is impossible to determine their type!") | |
{ | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var numbers = Scanf.Create(@"%i \+ %i \= %i").Matches("5+ 1 =6"); | |
numbers[0] == 5 | |
numbers[1] == 1 | |
numbers[2] == 6 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment