Arbeiten mit .NET: Grundlagen: Datentypen/ Zeichen und Zeichenketten
In diesem Kapitel behandeln wir die Datentypen System.Char (Zeichen) und System.String (Zeichenketten).
Überblick
BearbeitenDie 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
BearbeitenIm 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
BearbeitenDer 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).
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();
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()
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
BearbeitenFü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
BearbeitenHä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.
- 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:
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)));
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)))
String – eine Zeichenkette
BearbeitenDefinition
BearbeitenDer 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.
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);
}
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
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
BearbeitenSchon aus den Beispielen wird deutlich, dass Char-Werte und Strings bei verschiedenen Programmiersprachen unterschiedlich anzugeben sind.
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.
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
BearbeitenFü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.
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();
}
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
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
BearbeitenFü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?
- Der Datentyp Char steht für ein einzelnes Unicode-Zeichen.
- Der Datentyp Char ist ein Wertetyp.
- Ein Char kann durch eine ganze Zahl dargestellt werden.
- Ein Char kann maximal 232 verschiedene Werte darstellen.
- Mit Char.GetUnicodeCategory(c) kann festgestellt werden, ob es sich um eine Ziffer, einen Buchstaben, ein Satzzeichen usw. handelt.
- Der direkte Vergleich "ist größer als" zweier Zeichen ist nicht möglich.
- Zu einem Zeichen kann eine ganze Zahl addiert werden.
Übung 2 | Definitionen | Zur Lösung |
Welche der folgenden Aussagen sind richtig, welche sind falsch?
- Der Datentyp String steht für eine Menge von Unicode-Zeichen.
- Der Datentyp String ist ein Referenztyp.
- Ein String kann maximal 65536 Zeichen lang sein.
- Bei zwei String-Variablen mit dem gleichen Inhalt wird dieser doppelt im Arbeitsspeicher gespeichert.
- Einer String-Variablen kann jederzeit ein neuer Inhalt zugewiesen werden.
- Auch die Änderung eines einzelnen Zeichens innerhalb des Strings ist direkt möglich.
- Der direkte Vergleich "ist größer als" zweier Strings ist bei keiner .NET-Programmiersprache möglich.
- Beim Vergleich durch String.Compare können Besonderheiten von Zeichensätzen berücksichtigt werden.
- 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 |
- Deklarieren und initialisieren Sie zwei Char-Variable für die Buchstaben Ü und ü.
- Deklarieren und initialisieren Sie zwei Char-Variable für einfaches und doppeltes Anführungszeichen.
- Deklarieren und initialisieren Sie zwei Char-Variable für den Backslash und den horizontalen Tabulator.
- Deklarieren und initialisieren Sie eine String-Variable für den folgenden Text:
Die deutsche Ausgabe von "Harper's Bazaar" wurde eingestellt. - Deklarieren und initialisieren Sie eine String-Variable für den folgenden Dateipfad:
C:\WINDOWS\Microsoft.NET\Framework\v3.0\WPF\PresentationUI.dll
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 |
// 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";
// 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"