So,..

Bei mir hats nur für die Umwandlung von Zahlen in ihre Namen, das Erkennen von Zahlen in Texten und die Umsetzung von
Befehlen. (Also Aufgabe 1 und 2)
Jedoch hab ich auch noch die Unterstützung für Zahlen mit Dezimalstellen hinzugefügt.
Beispiel:
Code :
1
2
> 123,4567890
- - > einhundertdreiundzwanzig komma vier fünf sechs sieben acht neun null

Inhalt
  1. Navi Computer Klasse
  2. Formattierungsklasse
  3. Hilfsklassen und Extension Methods
  4. Das Testprogramm

Navi Computer Klasse
Analysiert Zeichenketten, findet Befehle und Zahlen, und ersetzt diese entsprechend.
Vorhande Befehle: /date /clock /version /pi
Code csharp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
 
namespace CodingQuiz13
{
    public class Navi
    {
        private static Regex numRegex = new Regex("\\d+([\\.,]\\d+)?", RegexOptions.Singleline | RegexOptions.Compiled);
        private static Regex macroRegex = new Regex("/[a-zA-Z]+", RegexOptions.Singleline | RegexOptions.Compiled);
 
        private Dictionary<string, Func<string, string>> Macros = new Dictionary<string, Func<string, string>>
        {
            { "/clock", delegate(string p) { return DateTime.Now.ToString("hh \"Uhr\" mm"); } },
            { "/date", delegate(string p) { return DateTime.Now.ToString("dd MMMM yyyy"); } },
            { "/version", delegate(string p) { return "Navi v0.1"; } },
            { "/pi", delegate(string p) { return Math.PI.ToString(); } }
        };
 
        private static NumberFormatter frmt = new GermanNumberFormatter();
 
        public string Process(string text)
        {
            var macros = FindMacros(text);
 
            text = text.Replace(macros, ExecuteMacro);
 
            var numbers = FindNumbers(text);
 
            return text.Replace(numbers, frmt.ToName).Trim();
        }
 
        private string ExecuteMacro(string macro)
        {
            if (!Macros.ContainsKey(macro))
                return macro;
 
            return Macros[macro](macro);
        }
 
        private PositionInfo[] FindMacros(string line)
        {
            var results = macroRegex.Matches(line);
 
            var infos = new PositionInfo[results.Count];
 
            for (int i = 0; i < infos.Length; i++)
            {
                infos[i] = new PositionInfo();
                Match match = results[i];
 
                infos[i].StartIndex = match.Index;
                infos[i].Text = match.Value;
            }
 
            return infos;
        }
 
        private PositionInfo[] FindNumbers(string line)
        {
            var results = numRegex.Matches(line);
 
            var infos = new PositionInfo[results.Count];
 
            for (int i = 0; i < infos.Length; i++)
            {
                infos[i] = new PositionInfo();
                Match match = results[i];
 
                infos[i].StartIndex = match.Index;
                infos[i].Text = match.Value;
            }
 
            return infos;
        }
 
    }
}

Formattierungsklasse
Zerlegt die Zahlen in Blöcke zu 3 Ziffern und formatiert diese. Je nach Stellung dieser Blöcke wird dann noch ein passender
Zahlenname angehängt (z.b. "Millionen") und das ganze zu einer Zeichenkette zusammengefasst.
Code csharp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System;
using System.Linq;
using System.Text;
 
namespace CodingQuiz13
{
    public abstract class NumberFormatter
    {
        public abstract string ToName(int number);
        public abstract string ToName(string number);
    }
 
    public class GermanNumberFormatter : NumberFormatter
    {
        private string[] digits = new string[] { "null", "ein", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun" };
        private string[] Zs = new string[] { "zehn", "zwanzig", "dreißig", "vierzig", "fünfzig", "sechzig", "siebzig", "achtzig", "neunzig", "hundert", "tausend" };
 
        private string[] prefixes = { "Mi", "Bi", "Tri", "Quadri", "Quinti", "Sexti", "Septi", "Okti", "Noni", "Dezi", "Undezi", "Duodezi", "Tredezi", "Quattuordezi", "Quindezi" };
        private string[] suffixes = { "llion", "lliarde" };
        private string[] plsuffixes = { "en", "n" };
 
        public override string ToName(int number)
        {
            return ToName(number.ToString());
        }
        public override string ToName(string number)
        {
            string dec = "";
            if (number.Contains('.') || number.Contains(','))
            {
                string[] p = number.Split('.', ',');
                dec = p[1];
                number = p[0];
            }
 
            int parts = number.Length / 3;
            int carry = number.Length % 3;
            bool plural = true;
 
            StringBuilder buffer = new StringBuilder();
 
            int start = 0;
            int end = carry;
            if (end == 0)
            {
                end = 3;
                parts -= 1;
            }
 
            for (int i = parts; i >= 0; i--)
            {
                string txt = number.Substring(start, end - start);
                int part = int.Parse(txt);
 
                if (part == 0 && parts == 0)
                    return digits[0];
 
                string formatted = FormatBlock(part, i);
 
                if (part == 1 && i > 1)
                {
                    formatted += "e";
                    plural = false;
                }
                else
                    plural = part > 1;
 
                buffer.Append(formatted);
 
                if (part != 0 && i != 0)
                {
                    if (i == 1)
                        buffer.Append(Zs[10]);
                    else if ((i - 2) < prefixes.Length * 2)
                    {
                        int p = (i - 2) / 2;
 
                        buffer.Append(" ");
                        buffer.Append(prefixes[p]);
                        buffer.Append(suffixes[i % 2]);
                        if (plural)
                            buffer.Append(plsuffixes[i % 2]);
                    }
                    else
                        buffer.Append(plural ? "hohe Etwase" : "hohes Etwas");
 
                    if (i > 1)
                        buffer.Append(" ");
                }
 
                start = end;
                end = start + 3;
            }
 
            if (!string.IsNullOrEmpty(dec))
            {
                buffer.Append(" komma ");
                buffer.Append(FormatDecimal(dec));
            }
 
            return buffer.ToString();
        }
 
        private string FormatDecimal(string dec)
        {
            StringBuilder buffer = new StringBuilder();
 
            foreach (char c in dec)
            {
                int d = int.Parse(c.ToString());
                buffer.Append(digits[d]);
                if (d == 1)
                    buffer.Append("s");
                buffer.Append(" ");
            }
 
            return buffer.ToString().TrimEnd();
        }
 
        private string FormatBlock(int number, int block)
        {
            int h = number / 100;
            int z = (number - h * 100) / 10;
            int e = (number - h * 100 - z * 10);
            string result = "";
 
            if (h > 0)
                result += digits[h] + Zs[9];
            if (z == 1)
            {
                if (e == 1)
                    result += "elf";
                else if (e == 2)
                    result += "zwölf";
                else if (e > 0)
                {
                    result += digits[e].Trim(4);
                    result += Zs[0];
                }
                else
                    result += Zs[0];
            }
            else
            {
                if (e > 0)
                    result += digits[e];
 
                if (e > 0 && z > 0)
                    result += "und";
 
                if (z > 0)
                    result += Zs[z - 1];
 
                if (z == 0 && e == 1 && block == 0)
                    result += "s";
            }
            return result;
        }
    }
}

Hilfsklassen und Extension Methods
2 Extension Methods für die String-Klasse. Einmal um den Text auf eine gewisse Länge zu kürzen, und eine zum Aufteilen
des Textes an den Positionen mit den Zahlen oder Befehlen und das Ersetzen dieser mit einem anderen Text. Die eine
Hilfsklasse speichert nur die Positionen der Zahlen/Befehle und deren string.
Code csharp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
 
namespace CodingQuiz13
{
    public static class Helpers
    {
        public static string Trim(this string text, int length)
        {
            if (text.Length < length)
                return text;
            return text.Substring(0, length);
        }
 
        public static string Replace(this string text, PositionInfo[] positions, Func<string, string> f)
        {
            StringBuilder buffer = new StringBuilder();
 
            int currentIndex = 0;
 
            foreach (PositionInfo p in positions)
            {
                if (p.StartIndex > 0)
                    buffer.Append(text.Substring(currentIndex, p.StartIndex - currentIndex));
 
                buffer.Append(f(p.Text));
                currentIndex = p.StartIndex + p.Text.Length;
            }
            if (currentIndex < text.Length)
                buffer.Append(text.Substring(currentIndex, text.Length - currentIndex));
 
            return buffer.ToString();
        }
    }
 
    public class PositionInfo
    {
        public int StartIndex { get; set; }
        public string Text { get; set; }
    }
}

Das Testprogramm
Hier wird der Navi-Computer benutzt.
Code csharp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using System;
using System.IO;
 
namespace CodingQuiz13
{
    class Program
    {
        static Navi navi = new Navi();
 
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                PrintUsage();
                return;
            }
 
            if (args[0] == "-i")
            {
                Interactive();
                return;
            }
 
            if (args[0] == "-t" && args.Length >= 2 && File.Exists(args[1]))
            {
                RunTestMode(args[1]);
                return;
            }
 
 
            if (!File.Exists(args[0]))
            {
                return;
            }
 
            using (StreamReader reader = new StreamReader(args[0]))
            {
                string line;
 
                while ((line = reader.ReadLine()) != null)
                    Console.WriteLine(navi.Process(line));
            }
 
        }
 
        private static void RunTestMode(string file)
        {
            int failed = 0;
            int c = 0;
 
            using (StreamReader reader = new StreamReader(file))
            {
                string line;
                string number;
                string result;
                string expected;
 
                while ((line = reader.ReadLine()) != null)
                {
                    number = c.ToString();
                    expected = line;
 
                    if (line.IndexOf(' ') >= 0)
                    {
                        string[] parts = line.Split(new char[] { ' ' }, 2);
 
                        number = parts[0];
                        expected = parts[1];
                    }
                    
                    result = navi.Process(number);
                        
                    
                    if (!result.Equals(expected))
                        failed++;
 
                    c++;
                }
 
            }
 
            Console.WriteLine("Done. {0} of {1} failed", failed, c);
            Console.ReadLine();
        }
 
        private static void Interactive()
        {
            Random rnd = new Random();
            string line;
 
            Console.Write("> ");
            while ((line = Console.ReadLine()) != "quit")
            {
                Console.Write("- - > {0}\r\n> ", navi.Process(line));
            }
 
        }
 
        static void PrintUsage()
        {
            Console.WriteLine("usage: CodingQuiz13 inputfile");
        }
    }
}