Forum: PC-Programmierung C# Strings in Koordinaten wandeln


von Torben (Gast)


Lesenswert?

Hallo, ich bin noch Anfänger in C# auf Windows Forms und lerne mit einem 
Projekt. Jetzt stehe ich mit einer Aufgabenstellung etwas auf dem 
Schlauch und zwar möchte ich eine Textdatei einlesen und die einzelnen 
Stringbuchstaben des kompletten Alphabets und nummerische Zeichen (case 
sensitive) in ein definiertes XY-Kooridnaten verbinden und an eine 
Funktion übergeben.

Textdatei:

Hallo

Ergibt in der Koordinatentabelle:
H = X: 12 Y:1
a = X: 15 Y:6
l = X: 18 Y:100
l = X: 18 Y:100
o = X: 200 Y:700

Die Datei einlesen über die Filestreammethode ist nicht das Problem, 
sondern wie ich jetzt die Buchstaben mit meinen Koordinaten verbinde. 
Also ich übergebe den kompletten String oder die Datei und das Programm 
weiss welche Koordinaten es sind.

Ich denke eine Lookuptabelle ist das richtige, aber irgendwie will der 
Groschen nicht fallen. Versteht mich nicht falsch, ich möchte kein 
fertiges Programm, sondern vielmehr ein Denkanstoss zur Lösung.

von Karl H. (kbuchegg)


Lesenswert?

Torben schrieb:

> H = X: 12 Y:1
> a = X: 15 Y:6
> l = X: 18 Y:100
> l = X: 18 Y:100
> o = X: 200 Y:700


Du liest erst  mal eine zeile als einen String ein.

Dann zerlegst du die Zeile anhand bekannter Trennstellen (zb 
Leerzeichen, zb Doppelpunkt) in einzelne Strings. Sieh dir dazu die 
String Methode 'split' an.

Nachdem du die komplette Zeile in geeignete Teile zerlegt hast, wendest 
du auf die dich interessierenden Teile eine der 'Convert' oder 'Parse' 
Methoden an, die dir Strings zum Beispiel in echte Zahlen konvertieren. 
Und die speicherst du dann so, wie du das brauchst. Zum Beispiel, in dem 
du dir eine Klasse machst, in der du die Kombination aus zu malendem 
Buchstaben und den jeweiligen Koordinatenwerten in einem Objekt 
vereingst. Die Summe aller Buchstaben könntest du dann in einem Array 
aus derartigen Objekten ablegen oder eben welcher Container zur 
Objektspeicherung dir sonst noch so gefällt.


Details zu jedem der Schritte findest du in jedem C# Lehrbuch bzw. 
Tutorial.

: Bearbeitet durch User
von Torben (Gast)


Lesenswert?

Hallo Karl Heinz,

ich hab mir ein Beispiel von MS abgeändert.
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Threading.Tasks;
6
using System.Diagnostics;
7
8
namespace ConsoleApplication3
9
{
10
    class Package
11
    {
12
        public string Letters;
13
        public int x;
14
        public int y;
15
    }
16
17
    class Program
18
    {
19
20
        
21
22
        public static void LookupExample()
23
        {
24
            // Create a list of Packages to put into a Lookup data structure.
25
            List<Package> packages = new List<Package> {    new Package { Letters = "Ha", x = 2, y = 2 },
26
                                                            new Package { Letters = "aa", x = 2, y = 3 },
27
                                                            new Package { Letters = "la", x = 2, y = 4 },
28
                                                            new Package { Letters = "la", x = 2, y = 5 },
29
                                                            new Package { Letters = "oa", x = 2, y = 6 }
30
                                                          };
31
32
            // Create a Lookup to organize the packages. Use the first character of Company as the key value.
33
            // Select Company appended to TrackingNumber for each element value in the Lookup.
34
            Lookup<char, string> lookup = (Lookup<char, string>)packages.ToLookup(p => Convert.ToChar(p.Letters.Substring(0, 1)),
35
                                                            p => p.Letters + " " + p.x + " " +p.y);
36
37
            // Iterate through each IGrouping in the Lookup and output the contents.
38
            foreach (IGrouping<char, string> packageGroup in lookup)
39
            {
40
                // Print the key value of the IGrouping.
41
                Console.WriteLine(packageGroup.Key);
42
                // Iterate through each value in the IGrouping and print its value.
43
                foreach (string str in packageGroup)
44
                    Debug.WriteLine("    {0}", str);
45
            }
46
47
            // Get the number of key-collection pairs in the Lookup.
48
            int count = lookup.Count;
49
50
            // Select a collection of Packages by indexing directly into the Lookup.
51
            IEnumerable<string> cgroup = lookup['H'];
52
53
            // Output the results.
54
            Debug.WriteLine("\nPackages that have a key of 'H':");
55
            foreach (string str in cgroup)
56
                Debug.WriteLine(str);
57
                                        
58
59
            // Determine if there is a key with the value 'G' in the Lookup.
60
            bool hasG = lookup.Contains('G');
61
        }
62
63
64
65
66
        static void Main(string[] args)
67
        {
68
69
            LookupExample();
70
71
72
73
        }
74
75
76
77
    }
78
}

Ich muss alle Zeichen in der Textdatei lesen, also auch Leerzeichen, 
Trenner gibt es nicht, aber das ist wohl nicht wild. Das Beispiel liesst 
noch nicht aus der Datei, aber das Verbinden der Buchstaben auf meine 
Kooridnaten klappt so. Ist natürlich mühselig das komplette Alpabet etc 
so zu wandeln, aber anders geht es wohl nicht.

Ist das ein guter Lösungsweg? Oder bin ich auf dem Holzweg?

von Karl H. (kbuchegg)


Lesenswert?

Torben schrieb:


> Ist das ein guter Lösungsweg?

Kann ich so nicht sagen, weil ich nicht weiss was das ganze iegentlich 
werden soll.

Aber aus
> Zum Beispiel, in dem du dir eine Klasse machst, in der du die
> Kombination aus zu malendem Buchstaben und den jeweiligen
> Koordinatenwerten in einem Objekt vereingst.

auf der einen Seite und
1
    class Package
2
    {
3
        public string Letters;
4
        public int x;
5
        public int y;
6
    }

zusammen mit
1
H = X: 12 Y:1
aus dem Datenfile schliesse ich, dass es genau darum geht aus der Zeile 
aus dem Datenfile ein Package Objekt zu erzeugen, bei dem
1
  Letter gleich "H"
2
  x gleich 12
3
  y gleich 1
sein soll.

Und der Weg dazu führt über String.split und geeignete Convert bzw. 
Parse Methoden die auf eine einzelne von der Datei eingelesene Zeile 
angewendet werden. Man kann natürlich auch die Zeile Buchstabe für 
Buchstabe auseinander nehmen und sich die Einzelteile zusammenbauen, 
wenn man das will. Man kann sich aber auch das Leben erst mal sehr viel 
einfacher machen, indem man die offensichtliche Struktur, die in jeder 
einzelnen Zeile der Datei steckt, sich zunutze macht.

Was du dann mit dem Package Objekt weiter machst, zum Beispiel wie in 
deinem geposteten Code zu einer
1
List<Package> packages
hinzufügen, das musst du wissen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Torben schrieb:

> Trenner gibt es nicht

natürlich gibt es sie. Oder woran erkennst du denn beim blossen 
Hinschauen, wie sich eine Zeile
1
l = X: 18 Y:100
strukturiert?

Ganz offensichtlich steht zwischen Buchstabe und den weiteren Angaben 
ein '='. Und ganz offensichtlich steht zwischen der 
Koordinatenbezeichnung und dem Zahlenwert ein ':'

Das sind deine Trenner, an denen man den String in Teile aufteilt.
Wenn aus dem aus dem File eingelesenen String
1
l = X: 18 Y:100
ein String Array geworden ist:
1
Array[0]  gleich "l"
2
Array[1]  gleich "X"
3
Array[2]  gleich "18"
4
Array[3]  gleich "Y"
5
Array[4]  gleich "100"
dann hast du alles beisammen um auf Array[2] und Array[4] jeweils die 
Convert Methode loszulassen und ein entsprechendes Package Objekt mit 
den Erkentnissen zu befüllen.

: Bearbeitet durch User
von Torben (Gast)


Lesenswert?

Hallo Karl Heinz,

ok jetzt hab ich dich verstanden.

Die Textdatei welche in die Koordinaten gewandelt werden muss hat keine 
Trenner, sondern muss von Anfang bis Ende gewandelt werden.

Die Tabelle mit der Referenzierung hat natürlich Trenner und kann somit 
gewandelt werden. Die Tabelle ist eine Exceldatei und kann auch in XML 
gewandelt werden, aber das ist Jacke wie Hose.

Ich hab mir die Parse-Methode angeschaut und die Möglichkeit mein 
Buchstaben in eine z.B. uint32 Zahl zu wandeln. Ich vermute das ich nun 
die Parse.enum nutzen soll um die Buchstaben in meine Koordinatenzahlen 
zu wandeln, oder?

von Torben (Gast)


Lesenswert?

Ok du warst schon ein paar Schritte weiter und nimmst die mühsellige 
Arbeit ab indem du die Tabelle in ein Package wandelst und dieses 
Package zum Parsen nimmst, dadurch wird es natürlich viel generischer 
als meine Lookuptabelle. Vielen Dank! Ich werd das mal ausprobieren.

von Karl H. (kbuchegg)


Lesenswert?

Ach. Jetzt versteh ich dich!

Mir war nicht klar, was Eingabe und was Ausgabe ist.

Du sollst aus
1
Hallo

das hier
1
H = X: 12 Y:1
2
a = X: 15 Y:6
3
l = X: 18 Y:100
4
l = X: 18 Y:100
5
o = X: 200 Y:700

erzeugen!
Ich dachte die ganze Zeit letzteres wäre der Input für dein Programm.

Ok. vergiss alles was ich gesagt habe. Ich bin von einer anderen 
Aufgabenstellung ausgegangen.

von B. S. (bestucki)


Lesenswert?

Karl H. schrieb:
>> Trenner gibt es nicht
>
> natürlich gibt es sie. Oder woran erkennst du denn beim blossen
> Hinschauen, wie sich eine Zeilel = X: 18 Y:100
> strukturiert?

Ich glaube, der TO will das Umgekehrte. 'H' ergibt ein X von 12 und ein 
Y von 1.

Eine einfache und sichere Methode ist ein switch. Dies ist jedoch mit 
viel Arbeit verbunden:
1
switch(Zeichen){
2
  case 'H': X = 12; Y = 1; break;
3
  /* usw... */
4
  default:
5
    /* Fehlerbehandlung */
6
}

Eine andere Möglichkeit ist, den numerischen Wert des Zeichens für eine 
Lookup-Tabelle zu verwenden:
1
X = X_Werte[Zeichen];
2
Y = Y_Werte[Zeichen];

Ich kenne deine genauen Werte nicht, aber evt. lassen sich diese zur 
Laufzeit berechnen.


Edit: zu langsam...

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

> und zwar möchte ich eine Textdatei einlesen und die einzelnen
> Stringbuchstaben des kompletten Alphabets und nummerische Zeichen
> (case sensitive) in ein definiertes XY-Kooridnaten verbinden

Da erhebt sich aber trotzdem immer noch die Frage:
woher weisst du, welche Koordinaten zu einem Buchstaben gehören?

Deine (bis jetzt einzige) Eingabe an das Programm lautet ja
1
Hallo
und mehr hast du bis jetzt nicht. Woher nimmst du die Information, dass 
zu einem 'H' die Koordinaten 12 und 1 gehören?

Das hier
1
            List<Package> packages = new List<Package> {    new Package { Letters = "Ha", x = 2, y = 2 },
2
                                                            new Package { Letters = "aa", x = 2, y = 3 },
3
                                                            new Package { Letters = "la", x = 2, y = 4 },
4
                                                            new Package { Letters = "la", x = 2, y = 5 },
5
                                                            new Package { Letters = "oa", x = 2, y = 6 }
6
                                                          };
ist zwar nett, aber willst du wirklich diesen Zusammenhang im Programm 
stehen haben? Oder ist das soweit in Ordnung wenn das so ist?

Dann allerdings verstehe ich das Problem wieder einmal nicht.
Das kann ja auch in C# nicht so schwer sein, einen einzelnen Buchstaben 
nach dem anderen aus einer Datei zu lesen, den gelesenen Buchstaben 
mittels
1
            IEnumerable<string> cgroup = lookup[ gelesener Buchstabe ];
auf die Package-Liste loszulassen, wobei wahrscheinlich im Idealfall nur 
1 Package übrig bleibt und aus dem darauf folgendem
1
           // Output the results.
2
            Debug.WriteLine("\nPackages that have a key of 'H':");
3
            foreach (string str in cgroup)
4
                Debug.WriteLine(str);
die enstprechende Umänderng zu machen, die dann in eine Datei schreibt 
anstatt auf den Debug Output

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

Karl H. schrieb:
> Da erhebt sich aber trotzdem immer noch die Frage:
> woher weisst du, welche Koordinaten zu einem Buchstaben gehören?

Eine flexible Lösung wäre natürlich, die entsprechenden Werte aus einer 
Datei zu lesen. Damit kämen dann wieder deine Beiträge zum Zuge. Wenn 
die Werte jedoch für alle Zeiten hart in Stein gemeisselt sind, würde 
ich mir den Mehraufwand nicht antun.

von Karl H. (kbuchegg)


Lesenswert?

be s. schrieb:

> Ich glaube, der TO will das Umgekehrte. 'H' ergibt ein X von 12 und ein
> Y von 1.

Ja, jetzt hab ichs auch kapiert.
Manchmal hat man aber auch Tomaten auf den Augen.

von Torben (Gast)


Lesenswert?

Entschuldigung das ich mich so unpräzise Ausgedrückt habe. Richtig ich 
muss Hallo in die XY Koordinaten speichern. Die Werte hab ich ermittelt 
und in eine Exceltabelle abgelegt, deshalb hat deine Antwort mir 
geholfen.

Ich lese die Tabelle und wandle wie in meinem Beispiel Sie in ein 
Package, danach vergleiche ich die "Hallo"-Datei mit der Lockuptable.

Die Switchcase Anweisung finde ich nicht so schon zu pflegen und kostet 
viel Verarbeitungszeit. Ich glaube eine Tabelle dürfte schneller und 
pflegeleichter sein. Leider ist nie etwas in steingemeiselt, deshalb 
finde ich die Idee auch die Tabelle einzulesen echt gut.

von Kleiner Max (Gast)


Lesenswert?

Torben schrieb:
> Ich lese die Tabelle und wandle wie in meinem Beispiel Sie in ein
> Package, danach vergleiche ich die "Hallo"-Datei mit der Lockuptable.

Das sieht ein wenig zu kompliziert aus (es geht da eher um die Erzeugung 
von Keys und die Gruppierung von Daten). Außerdem muss der Schlüssel - 
im Gegensatz zu deinem Schlüssel - in einem Lookup nicht eindeutig sein.

Man könnte es auch so ähnlich wie unten implementieren (falls ich das 
Problem richtig verstanden habe).

1
static class Extensions
2
{
3
  public static void ForEach<T>(this IEnumerable<T> value, Action<T> action)
4
  {
5
    foreach (T item in value) action(item);
6
  }
7
}
8
9
class Coordinate
10
{
11
  public Coordinate(int x, int y)
12
  {
13
    X = x;
14
    Y = y;
15
  }
16
17
  public Coordinate(string x, string y)
18
  {
19
    X = int.Parse(x);
20
    Y = int.Parse(y);
21
  }
22
23
  public override string ToString() => $"({X}, {Y})";
24
25
  public int X { get; }
26
  public int Y { get; }
27
}
28
29
class CoordinateTable
30
{
31
  public CoordinateTable(string path)
32
  {
33
    _dict = new Dictionary<char, Coordinate>();
34
    File.ReadLines(path).ForEach(line => AddTableEntry(line));
35
  }
36
  
37
  public int Count => _dict.Count;
38
39
  public Coordinate this[char key] => _dict[key];
40
41
  public IEnumerable<Coordinate> GetCoordinates(string s) => s.Select(c => _dict[c]);
42
43
  void AddTableEntry(string line)
44
  {
45
    if (!string.IsNullOrWhiteSpace(line))
46
    {
47
      var tokens = line.Split(Separators, StringSplitOptions.RemoveEmptyEntries);
48
49
      // Validieren ...
50
51
      _dict.Add(tokens[0][0], new Coordinate(tokens[1], tokens[2]));
52
    }
53
  }
54
55
  static readonly char[] Separators = { ',', ' ', '\t' };
56
  readonly Dictionary<char, Coordinate> _dict;
57
}
58
59
class Program
60
{
61
  static void Main(string[] args)
62
  {
63
    var table = new CoordinateTable("map.txt");
64
    
65
    Console.WriteLine(table['b']);
66
    Console.WriteLine();
67
68
    table.GetCoordinates("Hallo").ForEach(Console.WriteLine);
69
70
    Console.WriteLine();
71
  }
72
}

map.txt
1
A,    2,    3
2
B,    8,    2
3
C,    2, 3000
4
H,   12,    1
5
a,   15,    6
6
b, 1111,   42
7
c,   12,   99
8
l,   18,  100
9
o,  200,  700
10
0,    9,   23
11
1,    0,    0

Ausgabe
1
(1111, 42)
2
3
(12, 1)
4
(15, 6)
5
(18, 100)
6
(18, 100)
7
(200, 700)

Du kannst dir dann auch überlegen, was du machst, wenn der Schlüssel 
nicht vorhanden ist (hier wird eine Ausnahme geworfen, man könnte aber 
z.B. eine [0, 0]-Koordinate zurückgeben).

von Torben (Gast)


Lesenswert?

Hallo Kleiner Max,

wow, danke. Ich hab den Code noch nicht ganz verstanden und muss mir das 
genauer zu gemüte führen, damit ich es verstehe. Ich danke Dir für dein 
Bespiel

von nicht"Gast" (Gast)


Lesenswert?

Torben schrieb:
> wow, danke. Ich hab den Code noch nicht ganz verstanden und muss mir das
> genauer zu gemüte führen, damit ich es verstehe. Ich danke Dir für dein
> Bespiel

Kein Wunder. Kleiner Max schein aus der Pearl Ecke zu kommen. Was für 
eine furchtbar unübersichtliche Art zu programmieren ^^.

Grüße,

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.