Arbeiten mit .NET: Das Framework/ Basistechnologien/ Datentypen/ Zeichen und Zeichenketten

Aus Wikibooks
Wikipedia hat einen Artikel zum Thema:

In diesem Kapitel behandeln wir die Datentypen System.Char (Zeichen) und System.String (Zeichenketten).

Überblick[Bearbeiten]

Die folgende Übersicht enthält die hier behandelten Datentypen.

Klassenname CLS Typ Darstellung Standard Minimum Maximum
Char ja Wertetyp C# durch 'a'
VB durch "a"c
0x0000 U+0000 U+FFFF
String ja Referenztyp C# durch "abc"
VB durch "abc"
null String.Empty 231 Zeichen
ca. 2 GB Größe

Char – ein Zeichen[Bearbeiten]

Im Gegensatz zu früheren Programmiersystemen baut .NET vollständig und konsequent auf Unicode auf. Damit können bis zu 65.536 verschiedene Zeichen verarbeitet werden.

Aus der Frühzeit der EDV ist das Problem der nationalen Zeichen geblieben: Mit 1 Byte (= 8 Bit) können höchstens 256 Zeichen (abzüglich 32 Steuerzeichen sowie Ziffern und einer Reihe von Satz- und Sonderzeichen) dargestellt werden; und das reicht nicht einmal für die Akzentbuchstaben (Umlaute) aller westeuropäischen Sprachen. Erst durch Unicode gibt es einen Standard, der weltweit alle Zeichen (z.B. auch die chinesischen Zeichen) darstellen und speichern soll.

Allerdings enthält die Unicode-Definition inzwischen weit über 100.000 Zeichen. Ein Unicode-Zeichen wird deshalb durch ein bis vier Einzelzeichen dargestellt.

Definition[Bearbeiten]

Der Datentyp System.Char ist ein Wertetyp und steht für ein einzelnes Unicode-Zeichen. Er hat eine Größe von 2 Byte, also 16 Bit, und kann durch eine ganze Zahl angegeben werden. Üblich ist die Angabe als Hex-Wert mit vorangestelltem "U+", aber auch der jeweilige dezimale Zahlenwert kommt vor.

Das .NET Framework selbst verarbeitet ausschließlich Unicode-Zeichen (genauer: nach Unicode-Standard als UTF-16, bei dem jedes Zeichen als eine Folge von ein bis zwei 16-Bit-Ganzzahlen dargestellt wird). Andere Zeichensätze sind innerhalb von .NET-Anwendungen völlig irrelevant; lediglich beim Einlesen oder Speichern von Daten muss darauf geachtet werden, ob das "andere" Programm bzw. die Datenstruktur ebenfalls mit Unicode arbeitet (genauer: mit welcher Variante) oder welcher spezielle Zeichensatz verwendet wird.

Die Schreibweisen werden in den folgenden Beispielen deutlich gemacht: Neben den Grenzwerten werden alle deutschen Zeichen sowie die speziellen türkischen Zeichen ausgegeben (jeweils als Zeichen, dann als Hex-Wert und zuletzt als Dezimalwert).

C#-Quelltext
Console.WriteLine(((int)Char.MinValue).ToString() + " - " + ((int)Char.MaxValue).ToString());
char c1 = 'ß';
Console.WriteLine(String.Format("{0} = U+{1:X4} = d{1:d3}", c1, (int)c1));
string s = "Zwei Boxkämpfer jagen Eva quer durch Sylt.";
foreach(char c in s)
	Console.WriteLine(String.Format("{0} = U+{1:X4} = d{1:d3}", c, (int)c));
s = "ÇçğİiIıŞş";
foreach(char c in s)
	Console.WriteLine(String.Format("{0} = U+{1:X4} = d{1:d3}", c, (int)c));
Console.ReadKey();
VB.NET-Quelltext
Imports Microsoft.VisualBasic    ' wegen AscW zur Konvertierung von Char nach Integer

Dim c as Char
Console.WriteLine((AscW(Char.MinValue)).ToString() + " - " + (AscW(Char.MaxValue).ToString()))
c = "ß"c
Console.WriteLine(String.Format("{0} = U+{1:X4} = d{1:d3}", c, AscW(c)))
Dim s As String = "Zwei Boxkämpfer jagen Eva quer durch Sylt."
For Each c In s
	Console.WriteLine(String.Format("{0} = U+{1:X4} = d{1:d3}", c, AscW(c)))
Next c
s = "ÇçğİiIıŞş"
For Each c In s
	Console.WriteLine(String.Format("{0} = U+{1:X4} = d{1:d3}", c, AscW(c)))
Next c
Console.ReadKey()
Ausgabe
0 - 65535
ß = U+00DF = d223
Z = U+005A = d090
w = U+0077 = d119
e = U+0065 = d101
i = U+0069 = d105
  = U+0020 = d032
B = U+0042 = d066
// usw.
I = U+0049 = d073
ı = U+0131 = d305
Ş = U+015E = d350
ş = U+015F = d351

In der jeweils zweiten Zeile steht auch, wie ein Char-Wert im Code anzugeben ist:

  • in C# und C++ in einfache Hochkommata eingeschlossen:
    'ß'
  • in VB in doppelte Hochkommata eingeschlossen mit angehängtem 'c' oder 'C':
    "ß"c

Einzelheiten zu dieser Schreibweise, auch für spezielle Zeichen, siehe unten bei Darstellung im Code für Zeichenketten.

Operationen[Bearbeiten]

Für Char stehen die folgenden Möglichkeiten zur Verfügung:

  • Folgende Operatoren können verwendet werden:
    • Vergleiche zwischen Zeichen sind Größenvergleiche zwischen ihren Zahlenwerten und entsprechen wegen der Einordnung bei Unicode gleichzeitig der lexikalischen Einordnung (ohne Berücksichtigung der Zeichensätze).
    • Rechenoperationen zwischen Zeichen sind ebenso möglich wie zwischen Zahlen; sie entsprechen der Rechnung mit den Zahlenwerten der Zeichen. Addition und Subtraktion sind gängige Verfahren bei Zeichen, vor allem die Addition und Subtraktion von 1 zu einem vorhandenen Zeichen.
  • In den Abschnitten zu Typumwandlungen werden genauer behandelt:
    • Ein Zeichen kann wie im Beispiel durch ToString als String behandelt werden.
    • Ein Zeichen kann wie im Beispiel als ganze Zahl behandelt werden.
    • Umgekehrt kann jedes Zeichen eines Strings als Char behandelt werden.
    • Eine ganze Zahl kann nicht immer als Char bearbeitet werden, andere Zahlen überhaupt nicht.

Unicode-Kategorien[Bearbeiten]

Häufig möchte der Programmierer wissen, ob in einem String an einer bestimmten Stelle eine Ziffer oder ein Satzzeichen oder sonst etwas enthalten ist. Dazu sind die Unicode-Zeichen in Kategorien eingeteilt; diese Kategorien können durch .NET abgefragt werden. Die Liste aller Zeichen mit Kategorien und ein C#-Programm dazu sind unter Liste "aller" UniCode-Chars und der UnicodeCategory zu finden.

Es gibt zz. 30 Kategorien; für die Praxis sind in Deutschland die folgenden am wichtigsten. Für jedes Zeichen kann geprüft werden, ob es zu einer Kategorie gehört; dazu gibt es die Methode GetUnicodeCategory sowie verschiedene IsXxx-Prüfungen.

  • Zahlzeichen: DecimalDigitNumber (Dezimalziffern), LetterNumber (Buchstaben, z.B. die römischen Zahlzeichen), OtherNumber (andere Zahlzeichen, z.B. ½)
  • Buchstaben: LowercaseLetter, UppercaseLetter, OtherLetter
  • Satzzeichen: ClosePunctuation, ConnectorPunctuation, DashPunctuation, FinalQuotePunctuation, InitialQuotePunctuation, OpenPunctuation, OtherPunctuation
  • Trennzeichen: LineSeparator, ParagraphSeparator, SpaceSeparator
  • Symbole: CurrencySymbol, MathSymbol, OtherSymbol
  • Steuerzeichen: Control, nämlich die Zeichen U+0000 bis U+001F sowie U+007F bis U+009F
  • Ersatzzeichen: Surrogate, wenn ein Unicode-Zeichen durch mehr als ein Zeichen dargestellt wird

Einige Zuordnungen sind in der folgenden Tabelle zusammengefasst.

Einige Unicode-Zeichen und ihre Kategorien
  • Let = Letter
  • Dig = Digit
  • Sym = Symbol
  • Pun = Punctuation
  • Sep = Separator
  • Sur = Surrogate
  • Ctl = Control
 	 Num	 Hex	Let	Dig	Sym	Pun	Sep	WSp	Sur	Ctl
--	----	----	---	---	---	---	---	---	---	---
x	0120	0078	 x	  	  	  	  	  	  	  
y	0121	0079	 x	  	  	  	  	  	  	  
z	0122	007A	 x	  	  	  	  	  	  	  
{	0123	007B	  	  	  	 x	  	  	  	  
|	0124	007C	  	  	 x	  	  	  	  	  
}	0125	007D	  	  	  	 x	  	  	  	  
~	0126	007E	  	  	 x	  	  	  	  	  
 	0132	0084	  	  	  	  	  	  	  	 x
 	0133	0085	  	  	  	  	  	 x	  	 x
 	0134	0086	  	  	  	  	  	  	  	 x
 	0135	0087	  	  	  	  	  	  	  	 x
 	0160	00A0	  	  	  	  	 x	 x	  	  
¡	0161	00A1	  	  	  	 x	  	  	  	  
¢	0162	00A2	  	  	 x	  	  	  	  	  
£	0163	00A3	  	  	 x	  	  	  	  	  
¤	0164	00A4	  	  	 x	  	  	  	  	  
¥	0165	00A5	  	  	 x	  	  	  	  	  
¦	0166	00A6	  	  	 x	  	  	  	  	  
§	0167	00A7	  	  	 x	  	  	  	  	  

So können Sie jedes Zeichen abfragen:

C#-Quelltext
char c1 = 'ß', c2 = 'ç', c3 = 'Ş', c4 = '"';
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}",
	c1, Char.GetUnicodeCategory(c1),
	Char.IsLetterOrDigit(c1), Char.IsLower(c1), Char.IsPunctuation(c1)));
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}",
	c2, Char.GetUnicodeCategory(c2),
	Char.IsLetterOrDigit(c2), Char.IsLower(c2), Char.IsPunctuation(c2)));
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}",
	c3, Char.GetUnicodeCategory(c3),
	Char.IsLetterOrDigit(c3), Char.IsLower(c3), Char.IsPunctuation(c3)));
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}",
	c4, Char.GetUnicodeCategory(c4),
	Char.IsLetterOrDigit(c4), Char.IsLower(c4), Char.IsPunctuation(c4)));
VB.NET-Quelltext
Dim c1, c2, c3, c4 As Char
c1 = "ß"c
c2 = "ç"c
c3 = "Ş"c
c4 = """"c
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}", _
	c1, Char.GetUnicodeCategory(c1), _
	Char.IsLetterOrDigit(c1), Char.IsLower(c1), Char.IsPunctuation(c1)))
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}", _
	c2, Char.GetUnicodeCategory(c2), _
	Char.IsLetterOrDigit(c2), Char.IsLower(c2), Char.IsPunctuation(c2)))
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}", _
	c3, Char.GetUnicodeCategory(c3), _
	Char.IsLetterOrDigit(c3), Char.IsLower(c3), Char.IsPunctuation(c3)))
Console.WriteLine(String.Format("{0} ist {1} / Letter,Digit: {2}  Lower: {3}  Punct: {4}", _
	c4, Char.GetUnicodeCategory(c4), _
	Char.IsLetterOrDigit(c4), Char.IsLower(c4), Char.IsPunctuation(c4)))
Ausgabe
ß ist LowercaseLetter / Letter,Digit: True  Lower: True  Punct: False
ç ist LowercaseLetter / Letter,Digit: True  Lower: True  Punct: False
Ş ist UppercaseLetter / Letter,Digit: True  Lower: False  Punct: False
" ist OtherPunctuation / Letter,Digit: False  Lower: False  Punct: True


String – eine Zeichenkette[Bearbeiten]

Definition[Bearbeiten]

Der vordefinierte Datentyp System.String steht für eine Folge von Unicode-Zeichen. Er kann 0 bis 231 Zeichen enthalten. Auf jedes einzelne Zeichen kann per Index zugegriffen werden, wobei sich der Index 0 auf das erste Zeichen bezieht, der Index 1 auf das zweite Zeichen usw.

Ein String ist ein Referenztyp, der sich wie ein Wertetyp verhält. Das hat mehrere zunächst ungewohnte Eigenschaften zur Folge:

  • Ein String ist unveränderlich.
  • Jede Änderung an einem vorhandenen String erzeugt einen neuen String im Arbeitsspeicher.
  • Ein zweiter String mit exakt demselben Inhalt wird nicht doppelt gespeichert, sondern bekommt eine weitere Referenz auf den vorhandenen String.

Diese Informationen wollen wir wieder an einem Beispielprogramm verdeutlichen.

C#-Quelltext
static void Main(string[] args)
{
	string s1 = "Dies ist ein Text.";
	Console.WriteLine("s1[6] steht für das 7. Zeichen: " + s1[6]);
	Console.WriteLine(s1[6].GetType());
	Change(s1);
	Console.WriteLine("Main   (weiter): " + s1);
	string s2 = "Dies ist ein Text.";
	Console.WriteLine("Main   (für s2): " + s2);
	Console.WriteLine("s1 gleich s2 ? : " + (s1 == s2 ? "true" : "false"));
	Console.WriteLine("s1 Ref-Eq s2 ? : " + (Object.ReferenceEquals(s1, s2) ? "true" : "false"));
	s1 = "Jetzt ändern wir den Text und vergleichen erneut:";
	Console.WriteLine("s1 gleich s2 ? : " + (s1 == s2 ? "true" : "false"));
	Console.WriteLine("s1 Ref-Eq s2 ? : " + (Object.ReferenceEquals(s1, s2) ? "true" : "false"));
	s1 = String.Empty;
	Console.WriteLine("s1 ist jetzt " + s1.Length.ToString() + " Zeichen lang.");

	// Ein Versuch zur direkten Änderung ergibt eine Fehlermeldung:
	// s1[0] = 'x';
	// (Dafür) kann keine Zuweisung ausgeführt werden. Sie sind schreibgeschützt.
}
		
static void Change(string s1)
{
	Console.WriteLine("Change (Anfang): " + s1);
	s1 = "Jetzt folgt ein geänderter Text.";
	Console.WriteLine("Change  (Ende) : " + s1);
}
VB.NET-Quelltext
Sub Main()
	Dim s1 As String = "Dies ist ein Text."
	Console.WriteLine("s1(6) steht für das 7. Zeichen: " + s1(6))
	Console.WriteLine(s1(6).GetType())
	Change(s1)
	Console.WriteLine("Main   (weiter): " & s1)
	Dim s2 As String = "Dies ist ein Text."
	Console.WriteLine("Main   (für s2): " & s2)
	Console.WriteLine("s1 gleich s2 ? : " & IIf(s1 = s2, "true", "false"))
	Console.WriteLine("s1 Ref-Eq s2 ? : " & IIf(Object.ReferenceEquals(s1, s2), "true", "false"))
	s1 = "Jetzt ändern wir den Text und vergleichen erneut:"
	Console.WriteLine("s1 gleich s2 ? : " & IIf(s1 = s2, "true", "false"))
	Console.WriteLine("s1 Ref-Eq s2 ? : " & IIf(Object.ReferenceEquals(s1, s2), "true", "false"))
	s1 = String.Empty
	Console.WriteLine("s1 ist jetzt " & s1.Length.ToString() & " Zeichen lang.")
	
	' Ein Versuch zur direkten Änderung ergibt eine Fehlermeldung:
	' s1(0) = "x"c
	' Fehler BC30526: Die Eigenschaft Chars ist ReadOnly.
	Console.ReadKey()
End Sub
		
Sub Change(s1 As String)
	Console.WriteLine("Change (Anfang): " + s1)
	s1 = "Jetzt folgt ein geänderter Text."
	Console.WriteLine("Change  (Ende) : " + s1)
End Sub
Ausgabe
s1[6] steht für das 7. Zeichen: s
System.Char
Change (Anfang): Dies ist ein Text.
Change  (Ende) : Jetzt folgt ein geänderter Text.
Main   (weiter): Dies ist ein Text.
Main   (für s2): Dies ist ein Text.
s1 gleich s2 ? : true
s1 Ref-Eq s2 ? : true
s1 gleich s2 ? : false
s1 Ref-Eq s2 ? : false
s1 ist jetzt 0 Zeichen lang.

Mit dem Code und der Ausgabe sehen wir dies:

  • Die Zeichenkette s1 wird deklariert und initialisiert, also mit einem Anfangswert versehen.
  • Das 7. Zeichen kann am Index 6 ausgelesen werden; es ist tatsächlich kein kurzer String, sondern vom Typ System.Char.
  • Innerhalb der Methode Change kann der Wert von s1 geändert werden; diese Änderungen sind nach dem Ende von Change wieder "vergessen". Vergleichen Sie, was wir unter Wertetypen und Verweistypen unter "Werte zur Laufzeit ändern" gesagt haben: Dies ist das Verhalten von Wertetypen, nicht das Verhalten von Referenztypen. Aber String ist sozusagen etwas Besonderes.
  • Die Zeichenkette s2 wird deklariert und mit demselben Wert versehen.
  • Die beiden Vergleiche zeigen: Sowohl der Inhalt als auch die Referenzen von s1 und s2 sind gleich.
  • Anschließend bekommt s1 einen neuen Inhalt; beim erneuten Vergleich unterscheiden sich s1 und s2 sowohl beim Inhalt als auch bei den Referenzen.
  • Mit String.Empty wird ein "leerer String" von 0 Zeichen Länge erzeugt.
  • Eine direkte Änderung eines einzelnen Zeichens innerhalb eines Strings ist nicht möglich.

Selbstverständlich können Strings trotzdem geändert werden; ein paar Informationen dazu folgen im Abschnitt Wichtige Operationen. Sie müssen sich aber dessen bewusst sein, dass jede Änderung den Text im Arbeitsspeicher vollständig bearbeitet und unter Umständen viele Schritte zur Veränderung benötigt.

Eingabe im Code[Bearbeiten]

Schon aus den Beispielen wird deutlich, dass Char-Werte und Strings bei verschiedenen Programmiersprachen unterschiedlich anzugeben sind.

Eingabe bei C# und C++

Ein Char wird in einfache Hochkommata gesetzt, ein String in doppelte:

char c = 'x';           // dies ist ein Zeichen
string s1 = "x";        // dies ist ein String
string s2 = "Dies ist eine Zeichenkette.";

Einige Sonderzeichen sind speziell zu behandeln. Diese sind jeweils als „Escape-Sequenz“ anzugeben mit einem einleitenden Backslash und einer Angabe für die Bedeutung:

// die wichtigsten Zeichen:
char c1 = '\'';         // das einfache Anführungszeichen
char c2 = '\"';         // das doppelte Anführungszeichen
char c3 = '\\';         // der Backslash selbst
// ein beliebiges Unicode-Zeichen:
char c4 = '\u20ac';     // mit nachfolgendem Hex-Code, hier für das €-Zeichen
// weitere immer wieder einmal vorkommende Zeichen:
char c5 = '\r';         // der Wagenrücklauf "Carriage Return"
char c6 = '\n';         // der Zeilenumbruch "Newline"
char c7 = '\t';         // der horizontale Tabulator

Weitere Zeichen sind in der Praxis unter C# unwichtig. Die vollständige Liste ist in der Wikipedia unter Escape-Sequenzen für C u. a. aufgeführt. Das Fragezeichen kann bei C# direkt eingegeben werden.

Bitte beachten Sie: Es handelt sich in allen diesen Fällen um jeweils ein Zeichen. Lediglich für den Compiler und u.U. für den Debugger stehen zwei oder mehr Zeichen da. Überprüfen Sie das in einem kleinen Programm mit dem folgenden Code, der einfach alle vorstehenden Zeichen aufführt:

string s = "\'\"\\\r\n\t\u20ac";
Console.WriteLine(s + "\r\nLänge: " + s.Length);

String-Werte einfacher eingeben

Vor allem bei Pfadangaben verwirrt der doppelte Backslash sehr stark. Es gibt deshalb auch einen Weg, einen String-Wert „normal“ einzugeben.

  • Variante 1 (siehe oben): Der String steht innerhalb von Anführungszeichen; jedes Sonderzeichen ist mit Backslash anzugeben.
  • Variante 2: Vor das einleitende Anführungszeichen wird '@' gesetzt; dann wird jedes Zeichen so verstanden wie angegeben. Lediglich das Anführungszeichen ist zu verdoppeln.
  • Bei Variante 2 darf sogar ein Zeilenumbruch im String enthalten sein.

Bei Variante 2 wird der Begriff Verbatim-String verwendet.

// s1 und s2 sind völlig gleichwertig:
string s1 =  "C:\\CSharp\\Temp\\Versuch\\program.cs";
string s2 = @"C:\CSharp\Temp\Versuch\program.cs";
// ebenso s3 und s4:
string s3 =  "Faust stellte die \'Gretchenfrage\': \"Sag\', wie hältst du\'s mit der Religion?\"";
string s4 = @"Faust stellte die 'Gretchenfrage': ""Sag', wie hältst du's mit der Religion?""";
// auch so etwas ist möglich:
string s5 = @"Oh Mensch! Oh Mensch!
Gib Acht! Gib Acht!
Was spricht die tiefe Mitternacht?"
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.WriteLine(s1 == s2);     // ausdrückliche Prüfung auf Gleichheit
Console.WriteLine(s3);
Console.WriteLine(s4);
Console.WriteLine(s3 == s4);     // ausdrückliche Prüfung auf Gleichheit
Console.WriteLine(s5);

Anstelle von "\r\n" ist für den Zeilenumbruch vorzugsweise Environment.NewLine zu verwenden; das benutzt immer die korrekte Version für PC und Installation.

Die o.g. Zeichen sind als Escape-Sequenz mit Backslash anzugeben. Es handelt sich jeweils um ein Zeichen; nur für den Compiler und u.U. Debugger wird zusätzlich der Backslash angegeben (der aber nicht zählt). Zur Vereinfachung kann stattdessen vor den String-Wert ein '@' gesetzt werden.

Nebenbei bemerkt: Der Klammeraffe '@' gehört nur vor einen konkreten String-Wert. Vor einer String-Variablen ist er überflüssig und als Quatsch anzusehen.

Eingabe bei Visual Basic

Zeichen werden einheitlich in doppelte Hochkommata gesetzt. Standardmäßig interpretiert der Compiler das als String; mit nachgestelltem 'C' oder 'c' wird es als Char verstanden:

Dim c As Char = "x"c      ' dies ist ein Zeichen
Dim s1 As String = "x"    ' dies ist ein String
Dim s2 As String = "Dies ist eine Zeichenkette."

Als Sonderfall ist zu berücksichtigen, wenn ein Gänsefüßchen Teil des Strings ist. Dann ist es zu verdoppeln:

Dim s2 As String = "Dies zeigt mit ""Sonderfall"" ein Zitat."
' Ausgabe: Dies zeigt mit "Sonderfall" ein Zitat.

Bitte beachten Sie: Die doppelte Anführung zählt als ein Zeichen, wie es auch in der Ausgabe klar wird. Lediglich für den Compiler und u.U. für den Debugger werden zwei Anführungszeichen geschrieben.

Für Zeichen, die nicht einzeln mit der Tastatur geschrieben werden können, kann mit der ChrW-Funktion der Zahlenwert eingegeben werden:

Dim c1 As Char = ChrW(9)      ' für den horizontalen Tabulator
Dim c2 As Char = ChrW(13)     ' für den Wagenrücklauf "Carriage Return" CR
Dim c3 As Char = ChrW(10)     ' für eine neue Zeile "LineFeed" LF

Die beiden letzten Zeichen stehen also für den Zeilenumbruch CR/LF. Stattdessen ist aber vorzugsweise Environment.NewLine zu verwenden; das benutzt immer die korrekte Version für PC und Installation.

Operationen[Bearbeiten]

Für String stehen spezielle Möglichkeiten zur Verfügung, die zwangsläufig von denen bei Zahlen abweichen.

  • Folgende Operatoren können verwendet werden:
    • Vergleiche zwischen Strings sind standardmäßig Größenvergleiche zwischen den Zahlenwerten der Unicode-Zeichen. Bei VB kann auch mit '>' usw. verglichen werden; mit String.Compare können die Vergleiche genauer festgelegt werden, z.B. auch mit Berücksichtigung der Zeichensätze.
    • Verknüpfung von Strings ist durch '+' möglich; bei VB ist '&' vorzuziehen. Dieses Verfahren ist aber nur bedingt geeignet; sehr oft ist die Klasse StringBuilder sinnvoller.

Die wichtigsten Möglichkeiten für Strings werden hier kurz aufgeführt (mit den Variablen s1 und s2):

  • Ein leerer String wird vorzugsweise durch String.Empty festgelegt.
  • Mit String.IsNullOrEmpty(s1) wird geprüft, ob für s1 wirklich ein Wert zugewiesen wurde.
  • Mit String.Compare(s1, s2) werden zwei Strings einfach verglichen.
  • Mit s1.Contains(s2) kann geprüft werden, ob s2 in s1 enthalten ist; mit s1.IndexOf(s2) wird die genaue Position von s2 innerhalb von s1 bestimmt.
  • Mit s2 = s1.Substring(...) kann ein Teilstring bestimmt und separat verarbeitet werden.

Fast immer gibt es eine Reihe von Überladungen und Alternativen, die die Art der Prüfung genauer bestimmen. Es lohnt sich deshalb immer ein Blick in die .NET-Hilfe. Ein paar Möglichkeiten enthält das folgende Programm.

C#-Quelltext
static void Main(string[] args)
{
	string s1 = "Äpfel";
	string s2 = null;
	string s3 = String.Empty;
	// vergleiche null mit leer
	Console.WriteLine(s2 == s3 ? "s2 gleich s3" : "s2 ungleich s3");
	// verknüpfe s1 mit sich selbst: einmal mit Groß-, einmal mit Kleinbuchstaben
	if( String.IsNullOrEmpty(s2) )
	    s2 = s1.ToUpper() + " " + s1.ToLower();
	else
	    s2 = s1.ToLower() + " " + s1.ToUpper();
	Console.WriteLine(s2);
	// wo befindet sich der Text "el", unabhängig von der Schreibweise
	int i = s1.IndexOf("el", StringComparison.OrdinalIgnoreCase);
	// hole alles ab Position i
	s3 = s2.Substring(i);
	Console.WriteLine(s3);
	// hole ab Position i+2 die nächsten 5 Zeichen
	s3 = s2.Substring(i+2, 5);
	Console.WriteLine(s3);
	Console.ReadKey();
}
VB.NET-Quelltext
Sub Main()
	Dim s1 As String = "Äpfel"
	Dim s2 As String = Nothing
	Dim s3 As String = String.Empty
	' vergleiche Nothing mit leer
	Console.WriteLine(IIf(s2 = s3, "s2 gleich s3" , "s2 ungleich s3"))
	' verknüpfe s1 mit sich selbst: einmal mit Groß-, einmal mit Kleinbuchstaben
	If( String.IsNullOrEmpty(s2) ) Then
	    s2 = s1.ToUpper() & " " & s1.ToLower()
	Else
	    s2 = s1.ToLower() & " " & s1.ToUpper()
	End If
	Console.WriteLine(s2)
	' wo befindet sich der Text "el", unabhängig von der Schreibweise
	Dim i As Integer = s1.IndexOf("el", StringComparison.OrdinalIgnoreCase)
	' hole alles ab Position i
	s3 = s2.Substring(i)
	Console.WriteLine(s3)
	' hole ab Position i+2 die nächsten 5 Zeichen
	s3 = s2.Substring(i+2, 5)
	Console.WriteLine(s3)
	Console.ReadKey()
End Sub
Ausgabe
s2 ungleich s3  // bei VB: s2 gleich s3
ÄPFEL äpfel
EL äpfel
 äpfe

Nanu, bei C# und VB gibt es verschiedene Ergebnisse? Bei .NET soll es doch gleichgültig sein, womit programmiert wird? Nun, der VB-Compiler (und nur dieser!) erstellt bei IIf(s2 = s3) intern zunächst ausdrücklich Vergleiche auf Nothing und String.Empty und führt erst danach den "normalen" String-Vergleich durch. Damit wir nicht von solchen Dingen überrascht werden, merken wir uns:

Wir vergessen niemals, einen String auf null/Nothing und String.Empty zu überprüfen. Dazu benutzen wir immer String.IsNullOrEmpty.

Einzelheiten zu den verschiedenen Möglichkeiten werden in den Kapiteln über Zeichenkettenoperatoren sowie unter Strings und StringBuilder behandelt.

Verschiedene Sprachen[Bearbeiten]

.NET arbeitet, wie schon gesagt, intern ausschließlich mit Unicode-Zeichen. Die Besonderheiten einer Sprache, einer Schrift oder eines Landes können bei Bedarf gesteuert werden. Dies betrifft u.a. diese Situationen:

  • Der Vergleich zwischen Strings kann bei String.Compare(s1, s2, CultureInfo) durch kulturabhängige Informationen bestimmt werden; dazu wird die Klasse CompareInfo verwendet.
  • Zahlen und Datumsangaben können nach Bedarf als String speziell formatiert werden. Dazu werden Varianten der ToString-Methoden sowie die Klassen DateTimeFormatInfo und NumberFormatInfo verwendet.
  • Beim Einlesen und Speichern von Dateien mit abweichenden Zeichensätzen gibt es vielfältige Varianten unter Verwendung der Encoding-Klasse.

Mehr Informationen dazu gibt es in den o.g. Kapiteln sowie unter Grundlagen – Das Framework in den Kapiteln über "Zeichensätze und Formatierungen".

Zusammenfassung[Bearbeiten]

Für einzelne Zeichen gibt es den Char-Datentyp, für Zeichenketten die String-Klasse.

  • Es wird ausschließlich mit Unicode-Zeichen gearbeitet.
  • Ein String ist unveränderlich. Jede Änderung erzeugt einen neuen String.
  • Es gibt viele Möglichkeiten, Strings zu verarbeiten und auszuwerten.
  • Für Ein- und Ausgabe gibt es Varianten, die andere Zeichensätze berücksichtigen.

Aber das Wichtigste ist:

Merke
Ein String-Objekt ist unveränderlich. Es kann irgendwas um die 2 Milliarden Unicode-Zeichen enthalten.


Übungen[Bearbeiten]

Übung 1 Definitionen Zur Lösung

Welche der folgenden Aussagen sind richtig, welche sind falsch?

  1. Der Datentyp Char steht für ein einzelnes Unicode-Zeichen.
  2. Der Datentyp Char ist ein Wertetyp.
  3. Ein Char kann durch eine ganze Zahl dargestellt werden.
  4. Ein Char kann maximal 232 verschiedene Werte darstellen.
  5. Mit Char.GetUnicodeCategory(c) kann festgestellt werden, ob es sich um eine Ziffer, einen Buchstaben, ein Satzzeichen usw. handelt.
  6. Der direkte Vergleich "ist größer als" zweier Zeichen ist nicht möglich.
  7. Zu einem Zeichen kann eine ganze Zahl addiert werden.

Übung 2 Definitionen Zur Lösung

Welche der folgenden Aussagen sind richtig, welche sind falsch?

  1. Der Datentyp String steht für eine Menge von Unicode-Zeichen.
  2. Der Datentyp String ist ein Referenztyp.
  3. Ein String kann maximal 65536 Zeichen lang sein.
  4. Bei zwei String-Variablen mit dem gleichen Inhalt wird dieser doppelt im Arbeitsspeicher gespeichert.
  5. Einer String-Variablen kann jederzeit ein neuer Inhalt zugewiesen werden.
  6. Auch die Änderung eines einzelnen Zeichens innerhalb des Strings ist direkt möglich.
  7. Der direkte Vergleich "ist größer als" zweier Strings ist bei keiner .NET-Programmiersprache möglich.
  8. Beim Vergleich durch String.Compare können Besonderheiten von Zeichensätzen berücksichtigt werden.
  9. Es ist kein Unterschied bei der Prüfung, ob eine String-Variable null/Nothing ist oder ob sie den Wert String.Empty darstellt.

Übung 3 Schreibweisen Zur Lösung
  1. Deklarieren und initialisieren Sie zwei Char-Variable für die Buchstaben Ü und ü.
  2. Deklarieren und initialisieren Sie zwei Char-Variable für einfaches und doppeltes Anführungszeichen.
  3. Deklarieren und initialisieren Sie zwei Char-Variable für den Backslash und den horizontalen Tabulator.
  4. Deklarieren und initialisieren Sie eine String-Variable für den folgenden Text:
    Die deutsche Ausgabe von "Harper's Bazaar" wurde eingestellt.
  5. Deklarieren und initialisieren Sie eine String-Variable für den folgenden Dateipfad:
    C:\WINDOWS\Microsoft.NET\Framework\v3.0\WPF\PresentationUI.dll
Lösungen

Lösung zu Übung 1 Definitionen Zur Übung

Die Aussagen 1, 2, 3, 5, 7 sind richtig, die Aussagen 4, 6 sind falsch.

Lösung zu Übung 2 Definitionen Zur Übung

Die Aussagen 1, 2, 5, 8 sind richtig, die Aussagen 3, 4, 6, 7, 9 sind falsch.

Lösung zu Übung 3 Schreibweisen Zur Übung
C#-Quelltext
// zu 1.
char c1a = 'Ü';
char c1b = 'ü';
// zu 2.
char c2a = '\'';
char c2b = '\"';
// zu 3.
char c3a = '\\';
char c3b = '\t';
// zu 4.
string s4a = "Die deutsche Ausgabe von \"Harper\'s Bazaar\" wurde eingestellt.";
string s4b = @"Die deutsche Ausgabe von ""Harper's Bazaar"" wurde eingestellt.";
// zu 5.
string s5a = "C:\\WINDOWS\\Microsoft.NET\\Framework\\v3.0\\WPF\\PresentationUI.dll";
string s5b = @"C:\WINDOWS\Microsoft.NET\Framework\v3.0\WPF\PresentationUI.dll";
VB.NET-Quelltext
// zu 1.
Dim c1a As Char = "Ü"c
Dim c1b As Char = "ü"c
// zu 2.
Dim c2a As Char = "'"c
Dim c2b As Char = """"c
// zu 3.
Dim c3a As Char = "\"c
Dim c3b As Char = ChrW(9)
// zu 4.
Dim s4 As String = "Die deutsche Ausgabe von ""Harper's Bazaar"" wurde eingestellt."
// zu 5.
Dim s5 As String = "C:\WINDOWS\Microsoft.NET\Framework\v3.0\WPF\PresentationUI.dll"