// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Spludlow { public static class SimpleEncoding { public static List SimpleTypes = new List(new string[] { "Byte", "String", "String[]", "Char", "Char[]", "Int16", "Int16[]", "Int32", "Int32[]", "Int64", "Int64[]", "UInt16", "UInt16[]", "UInt32", "UInt32[]", "UInt64", "UInt64[]", "Single", "Single[]", "Double", "Double[]", "Decimal", "Decimal[]", "DateTime", "DateTime[]", "TimeSpan", "TimeSpan[]", "Boolean", "Boolean[]", "Type", "Type[]", }); public static bool IsSimple(Type type) // shouldn't use as type needs to exist in app domain { return IsSimple(type.Name); } public static bool IsSimple(string typeName) { typeName = ShortTypeName(typeName); return SimpleTypes.Contains(typeName); } public static string ShortTypeName(string assemblyQualifiedName) { if (assemblyQualifiedName.Contains(",") == true) { assemblyQualifiedName = assemblyQualifiedName.Substring(0, assemblyQualifiedName.IndexOf(",")); assemblyQualifiedName = assemblyQualifiedName.Substring(assemblyQualifiedName.LastIndexOf(".") + 1); } return assemblyQualifiedName; } public static string Encode(object data, string typeName) { if (data == null || data.GetType() == typeof(DBNull)) return ""; StringBuilder text = null; if (typeName.EndsWith("[]") == true) text = new StringBuilder(); switch (typeName) { case "Byte": return ((Byte)data).ToString(); case "String": return EncodeText((String)data); case "String[]": foreach (string item in (string[])data) { if (text.Length > 0) text.Append("\t"); text.Append(EncodeText(item)); } return text.ToString(); case "Char": return EncodeText(((Char)data).ToString()); case "Char[]": foreach (char item in (char[])data) { if (text.Length > 0) text.Append("\t"); text.Append(EncodeText(item.ToString())); } return text.ToString(); case "Int16": return ((Int16)data).ToString(); case "Int32": return ((Int32)data).ToString(); case "Int32[]": foreach (Int32 item in (Int32[])data) { if (text.Length > 0) text.Append("\t"); text.Append(item.ToString()); } return text.ToString(); case "UInt32[]": foreach (UInt32 item in (UInt32[])data) { if (text.Length > 0) text.Append("\t"); text.Append(item.ToString()); } return text.ToString(); case "Int64": return ((Int64)data).ToString(); case "UInt16": return ((UInt16)data).ToString(); case "UInt16[]": foreach (UInt16 item in (UInt16[])data) { if (text.Length > 0) text.Append("\t"); text.Append(item.ToString()); } return text.ToString(); case "UInt32": return ((UInt32)data).ToString(); case "UInt64": return ((UInt64)data).ToString(); case "Single": return ((Single)data).ToString(); case "Double": return ((Double)data).ToString(); case "Decimal": return ((Decimal)data).ToString(); case "Decimal[]": foreach (Decimal item in (Decimal[])data) { if (text.Length > 0) text.Append("\t"); text.Append(item.ToString()); } return text.ToString(); case "DateTime": return ((DateTime)data).ToString(); case "DateTime[]": foreach (DateTime item in (DateTime[])data) { if (text.Length > 0) text.Append("\t"); text.Append(item.ToString()); } return text.ToString(); case "TimeSpan": return ((TimeSpan)data).ToString(); case "TimeSpan[]": foreach (TimeSpan item in (TimeSpan[])data) { if (text.Length > 0) text.Append("\t"); text.Append(item.ToString()); } return text.ToString(); case "Boolean": return ((Boolean)data).ToString(); case "Type": return ((Type)data).Name; default: throw new ApplicationException("Simple Encode Type not supported:\t" + typeName); } } public static object Decode(string text, string typeName) { if (text.Length == 0) return null; if (Char.IsLower(typeName[0]) == true) // bodge to fix types lower case passed in paramters -P0String[] { StringBuilder typeText = new StringBuilder(typeName); if (typeText[0] == 'u') typeText[1] = Char.ToUpper(typeText[1]); typeText[0] = Char.ToUpper(typeText[0]); typeName = typeText.ToString(); } string[] words = null; if (typeName.EndsWith("[]") == true) words = Spludlow.Text.Split(text, '\t'); switch (typeName) { case "Byte": return Byte.Parse(text); case "String": return DecodeText(text); case "String[]": List strings = new List(); foreach (string word in words) strings.Add(DecodeText(word)); return strings.ToArray(); case "Char": return DecodeText(text)[0]; case "Char[]": List chars = new List(); foreach (string word in words) chars.Add(DecodeText(word)[0]); return chars.ToArray(); case "Int16": return Int16.Parse(text); case "Int32": return Int32.Parse(text); case "Int32[]": List int32s = new List(); foreach (string word in words) int32s.Add(Int32.Parse(word)); return int32s.ToArray(); case "Int64": return Int64.Parse(text); case "UInt16": return UInt16.Parse(text); case "UInt32": return UInt32.Parse(text); case "UInt64": return UInt64.Parse(text); case "Single": return Single.Parse(text); case "Double": return Double.Parse(text); case "Decimal": return Decimal.Parse(text); case "DateTime": return DateTime.Parse(text); case "TimeSpan": return TimeSpan.Parse(text); case "Boolean": return Boolean.Parse(text); case "Type": return Type.GetType("System." + text, true); // Use TypeCode ? default: throw new ApplicationException("Simple Decode Type not supported:\t" + typeName); } } private static string EncodeText(string input) { if (input == null) return ""; if (input == "") return "\"\""; return input; } private static string DecodeText(string input) { if (input == "") return null; if (input == "\"\"") return ""; return input; } public static Type Guess(string text) { int spaceCount = 0; int digitCount = 0; int letterCount = 0; int symbolCount = 0; Dictionary symbols = new Dictionary(); bool isArray = false; int tabIndex = text.IndexOf("\t"); if (tabIndex != -1) { isArray = true; text = text.Substring(0, tabIndex); // If an array guess on first } foreach (char ch in text) { if (ch == ' ') { ++spaceCount; continue; } if (Char.IsDigit(ch) == true) { ++digitCount; continue; } if (Char.IsLetter(ch) == true) { ++letterCount; continue; } ++symbolCount; if (symbols.ContainsKey(ch) == false) symbols.Add(ch, 1); else ++symbols[ch]; } // Date or Date Time if (letterCount == 0 && digitCount >= 6 && OnlyContains(symbols, new char[] { '/', ':' }, false) > 0) { int slash = SymbolCount(symbols, '/'); int colon = SymbolCount(symbols, ':'); if (slash == 2 && (colon >= 0 || colon <= 2)) return (isArray == false ? typeof(DateTime) : typeof(DateTime[])); } // Decimal or Integer if (letterCount == 0 && digitCount > 0 && spaceCount == 0 && OnlyContains(symbols, new char[] { '-', '.' }, true) >= 0) { if (SymbolCount(symbols, '-') == 0 || text[0] == '-') { if (symbols.ContainsKey('.') == true) return (isArray == false ? typeof(Decimal) : typeof(Decimal[])); else return (isArray == false ? typeof(Int32) : typeof(Int32[])); } } // Boolean string textToLower = text.ToLower(); if (textToLower == "true" || textToLower == "false") return (isArray == false ? typeof(Boolean) : typeof(Boolean[])); // String return (isArray == false ? typeof(String) : typeof(String[])); } private static int SymbolCount(Dictionary symbols, char testChar) { if (symbols.ContainsKey(testChar) == false) return 0; return symbols[testChar]; } private static int OnlyContains(Dictionary symbols, char[] characters, bool once) { List characterList = new List(characters); foreach (char testChar in symbols.Keys) { if (characterList.Contains(testChar) == false) return -1; } int found = 0; foreach (char testChar in characterList) { if (symbols.ContainsKey(testChar) == false) continue; if (once == true && symbols[testChar] != 1) return -1; ++found; } return found; } public static void GuessTest() { string[] tests = new string[] { "1/1/2019", "1/10/2019", "1/1/2019", "1/10/2019 1:00", "22/12/2019 12:00", "22/12/2019 12:45", "1/10/2019 1:00:11", "22/12/2019 12:00:22", "22/12/2019 12:45:33", "22/12", "22/12/29", "10:22", "00:00:00", "44:44:44:44:44:44", "1", "12123412", "123123.123123123", "-12312", "-123123.123123", "--34", "45-", "4-5", "4..5", "true", "false", "False", "TRUE", "fred" }; StringBuilder output = new StringBuilder(); foreach (string test in tests) output.AppendLine(Spludlow.SimpleEncoding.Guess(test).Name + "\t" + test); Spludlow.Log.Report("Guess Test", output.ToString()); } } }