5. Darstellung und Verarbeitung von Textzeichen

Werbung
1
5. Darstellung und Verarbeitung von Textzeichen
5.1. Einführung
Computer werden nicht nur zum Rechnen mit Zahlen oder zur Verarbeitung aussagenlogischer
Werte eingesetzt. Man kann mit ihnen auch Texte speichern und verarbeiten. Bei der Programmierung unterscheidet man Textzeichen und Zeichenketten:
• Ein (Text-)Zeichen (engl. Character) ist ein einzelnes Zeichen, wie beispielsweise ein lateinischer Buchstabe (A, ..., Z, a, ..., z), eine Ziffer (0, ..., 9), ein Sonderzeichen (!, ?, #, ’, +, -,
....), oder ein Schriftzeichen aus einem anderen Alphabet oder einer anderen Sprache (Russisch mit dem kyrillischen Alphabet, Griechisch, Arabisch, Hebräisch, Chinesisch, Japanisch, ...).
• Eine Zeichenkette (engl. String) ist eine Folge von Zeichen, wie beispielsweise die Wörter,
Sätze, Abschnitte und Programmbeispiele dieses Texts. Eine Zeichenkette kann auch nur ein
einziges Zeichen enthalten oder gar keines, also leer sein.
5.2. Standards zur Zeichencodierung
Computer speichern und verarbeiten Daten in binärer Form, also durch Nullen und Einsen. Ein
Zeichen kann dabei dargestellt („codiert“) werden, indem man ihm eine natürliche Zahl (also
eine nichtnegative ganze Zahl) zuordnet und dann deren Binärdarstellung im Speicher ablegt.
Benötigt wird also ein Standard, der jedem möglichen Zeichen eine eindeutige natürliche Zahl
zuordnet, so dass man von der gespeicherten Zahl eindeutig auf das Zeichen schließen kann.
Java benutzt zur Zeichencodierung den Unicode-Standard, der eine Erweiterung des ASCIIStandards ist.
5.2.1. ASCII
ASCII („American Standard Code for Information Interchange“) ist ein „7-Bit-Code“. Er stellt
also ein Zeichen durch eine Kombination aus sieben Bits dar, d.h. eine natürliche Zahl zwischen
0 und 127. ASCII umfasst
• die Ziffern 0 - 9
• die lateinischen Groß- und Kleinbuchstaben: A - Z, a - z
• Sonderzeichen wie (, ), !, ., :, *, #, +
• Steuerzeichen wie Zeilenvorschub, Seitenvorschub oder Tabulator
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
2
Die Codierung der 128 ASCII-Zeichen wird durch die ASCII-Tabelle definiert:
0
16
32
48
64
80
96
112
+0
NUL
DLE
Leerz.
0
@
P
`
p
+1
SOH
DC1
!
1
A
Q
a
q
+2
STX
DC2
"
2
B
R
b
r
+3
ETX
DC3
#
3
C
S
c
s
+4
EOT
DC4
$
4
D
T
d
t
+5
ENQ
NAK
%
5
E
U
e
u
+6
ACK
SYN
&
6
F
V
f
v
+7
BEL
ETB
'
7
G
W
g
w
+8
BS
CAN
(
8
H
X
h
x
+9
HT
EM
)
9
I
Y
i
y
+10
LF
SUB
*
:
J
Z
j
z
+11
VT
ESC
+
;
K
[
k
{
+12
FF
FS
,
<
L
\
l
|
+13
CR
QS
-
=
M
]
m
}
+14
SO
RS
.
>
N
^
n
~
+15
SI
US
/
?
O
_
o
DEL
• Der ASCII-Code eines Zeichens ergibt sich als Summe der Beschriftungen seiner Zeile und
Spalte.
• Beispiele:
Der ASCII-Code des Zeichens 'A' ist 65 (= 64 + 1).
Der ASCII-Code des Zeichens 'a' ist 97 (= 96 + 1).
Der ASCII-Code des Zeichens '+' ist 43 (= 32 + 11).
Der ASCII-Code des Leerzeichens ' ' ist 32 (= 32 + 0).
Der ASCII-Code des Zeilenvorschubs (Linefeed) 'LF' ist 10 (= 0 + 10).
• Gleichartige Zeichen stehen (bis auf wenige Ausnahmen) in zusammenhängenden Bereichen
der Tabelle, werden also durch Zahlen eines Intervalls codiert:
• Großbuchstaben im Intervall [65,90]
• Kleinbuchstaben im Intervall [97,122]
• Ziffern im Intervall [48,57]
• Steuerzeichen im Intervall [0,31] und bei 127
[Die meisten dieser Steuerzeichen haben heute kaum noch Bedeutung. Ausnahmen sind
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
3
BS = Backspace = Rückwärtsschritt, LF = Line Feed = Zeilenvorschub, FF = Form Feed
= Seitenvorschub, CR = Carriage Return = Ende der Eingabe und DEL = Delete = Löschen eines Zeichens]
Aufgabe 1: Was ist der ASCII-Code des Fragezeichens und was ist der Code der schließenden eckigen Klammer? Welches Zeichen codiert die Zahl 95 und welches die Zahl 120?
ASCII ist zwar ein 7-Bit-Code, aus praktischen Gründen werden ASCII-codierte Zeichen aber
in einem Byte, also acht Bits gespeichert. Das achte Bit kann für eine Erweiterung des Zeichensatzes genutzt werden, also zur Codierung weiterer Zeichen durch die Codes 128, ..., 255. Ein
Beispiel für eine solche Erweiterung ist Latin-1, das u.a. Umlaute (ä, ö, ...) und Vokale mit Akzent (á, à, ...) umfasst.
ASCII und seine 8-Bit-Erweiterungen sind durch die ISO (International Organization for Standardization) standardisiert, so z.B. Latin-1 als ISO-Standard 8859-1.
5.2.2. Unicode
ASCII berücksichtigt nur eine sehr kleine Teilmenge der weltweit benutzten Zeichen. Um dem
abzuhelfen, wurde Unicode eingeführt. Unicode ist in seiner ursprünglichen Form ein 16-BitCode; später wurde er auf 32 Bits erweitert. Unicode-Zeichen werden also binär in Zwei- oder
Vier-Byte-Variablen gespeichert.
Der Zahlenbereich 0-255 von Unicode entspricht ASCII Latin-1. Höhere Zahlen codieren die
Zeichensätze weiterer Schriftsprachen, z.B. das kyrillische Alphabet ab 1024 oder die chinesischen Schriftzeichen ab 19968.
Unicode ist unter der ISO-Nummer 10646 standardisiert. Näheres (auch zu ASCII und seinen
Erweiterungen) findet man unter http://www.unicode.org.
Aufgabe 2: Gehen Sie zu http://www.unicode.org/charts/ um zu sehen, welche Alphabete und
Sprachen in Unicode berücksichtigt sind.
5.3. Zeichen in Java
5.3.1. Zeichenkonstanten
Java basiert auf dem 16-Bit-Unicode. Einzelzeichen werden also durch zwei Bytes codiert, wie
durch die Unicode-Tabellen festgelegt. Relevant für den deutsch- und englischsprachigen
Raum ist dabei der Zahlenbereich von 0 bis 255, der ASCII Latin-1 entspricht.
In Java kann man eine Zeichenkonstante (also einen Wert aus dem Unicode-Zeichensatz) auf
verschiedene Arten schreiben:
• Das Zeichen in '' (also in einfachen Hochkommata)
• Beispiele: 'A' 'a' 'α' '#'
• Die „Unicode-Escape-Sequenz“ des Zeichens. Sie hat die Form '\uxxxx', wobei xxxx
für die vier Hexadezimalziffern steht, die den Unicode des Zeichens angeben.
• Beispiele: '\u0041' für A, '\u0061' für a, '\u03B1' für α, '\u0023' für #
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
4
• Randbemerkung: Man kann solche Sequenzen an jeder beliebigen Stelle des Java-Quelltexts einsetzen, also z.B. in Zeichenketten (siehe nächster Abschnitt) oder in Variablennamen.
• Für spezielle Zeichen: Eine „Java-Escape-Sequenz“ der Form '\x', wobei x für ein Zeichen gemäß der folgenden Tabelle steht.
Bezeichnung
Zeichen
BS (Back Space, Schritt nach links)
'\b'
HT (horizontaler Tabulator)
'\t'
LF (Line Feed, Zeilenende)
'\n'
FF (Form Feed, vertikaler Tabulator)
'\f'
CR (Carriage Return, Wagenrücklauf)
'\r'
" (doppeltes Hochkomma)
'\"'
' (einfaches Hochkomma)
'\''
\ (Back Slash, umgekehrter Schrägstrich)
'\\'
5.3.2. Zeichenvariablen
Der Java-Typ für einzelne Zeichen heißt char. Sein Wertebereich ist die Menge der Zahlencodes gemäß 16-Bit-Unicode. char-Konstanten in Java-Programmen werden dargestellt wie
im vorangehenden Abschnitt beschrieben.
• Beispiel: Deklaration und Initialisierung zweier char-Variablen
char a='A', b='\u0023';
Aufgabe 3: Deklarieren Sie eine char-Variable und weisen Sie ihr das Zeichen α zu. Berücksichtigen Sie dabei, dass dieses Zeichen auf Ihrer Tastatur nicht vorhanden ist, Sie es also
nicht direkt eintippen können.
char-Werte werden durch System.out.println() ausgegeben. Ein char-Wert wird
durch System.in.read() eingelesen. Da read() einen Ganzzahlwert liefert, muss dieser
Wert explizit nach char umgewandelt werden.
• Beispiel: Ausgabe zweier char-Werte und Einlesen eines char-Werts
char a = ..., b = ...;
System.out.println("a = "+a+" b = "+b);
char c = (char) System.in.read();
Die Java-Klasse Character definiert eine Reihe nützlicher Methoden zum Umgang mit
char-Werten. Der folgende Programmausschnitt zeigt einige von ihnen:
• Beispiel: Einige Methoden der Klasse Character
char c = ...;
System.out.println("Ist es ein Buchstabe? "
+Character.isLetter(c));
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
5
System.out.println("Ist es ein Grossbuchstabe? "
+Character.isUpperCase(c));
System.out.println("Ist es ein Kleinbuchstabe? "
+Character.isLowerCase(c));
System.out.println("Ist es eine Ziffer? "
+Character.isDigit(c));
System.out.println("Ist es eine Ziffer oder ein Buchstabe? "
+Character.isLetterOrDigit(c));
System.out.println("Entsprechender Grossbuchstabe: "
+Character.toUpperCase(c));
System.out.println("Entsprechender Kleinbuchstabe: "
+Character.toLowerCase(c));
Da char-Werte intern als ganze Zahlen dargestellt werden, kann man mit ihnen rechnen. Beispielsweise kann man für ein Zeichen seinen Vorgänger und seinen Nachfolger in der UnicodeTabelle ermitteln – im Fall von Buchstaben also den vorherigen und den nächsten Buchstaben
im Alphabet.
• Beispiel: Ermittlung des Vorgängers und des Nachfolgers eines char-Werts
char c = ...;
char vorgaenger = (char)(c-1);
char nachfolger = (char)(c+1);
Aufgabe 4: Welchen Wert hat der Ausdruck (char)('m'-5)? Welchen Wert hat der Ausdruck
(char)('9'+4)?
Entsprechend sind sämtliche Wertvergleiche, die in Kap. 4 eingeführt wurden, zulässig:
==, !=, <, <=, >, >=.
Aufgabe 5: Laden Sie das Programmbeispiel http://www.nt.th-koeln.de/vogt/dv/java/Daten/
Chars.java herunter, führen Sie es aus und vollziehen Sie seine Operationen im Quellcode
nach. Verändern und erweitern Sie es nach Ihren eigenen Ideen.
5.4. Zeichenketten / Strings in Java
5.4.1. Konstanten für Zeichenketten
Konstante Zeichenketten („Stringkonstanten“) werden in Java durch Zeichenfolgen dargestellt,
die in "" eingeschlossen sind (also in doppelten Hochkommata = dem Zeichen, das sich auf einer deutschen Tastatur oberhalb des Zeichens 2 befindet). Hierbei sind beliebige Unicode-Zeichen zugelassen, auch in ihrer Darstellung als Escape-Sequenzen.
• Beispiele: "Hallo" "Erste Zeile\nZweite Zeile" "alpha: \u03b1"
• Achtung: Man muss gut unterscheiden zwischen Einzelzeichen und Zeichenketten. Beispielsweise ist 'c' eine char-Konstante, "c" ist dagegen eine Stringkonstante der Länge
1. Es handelt sich dabei um unterschiedliche, nicht direkt kompatible Werte und Typen!
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
6
5.4.2. Variablen: Klasse String
Stringkonstanten und -variablen können in Java mit dem Typ String realisiert werden. Für
das grundlegende Verständnis dieses Typs sind die folgenden Begriffe und Zusammenhänge
wichtig:
• String-Objekte speichern String-Konstanten.
• String-Variablen speichern Referenzen auf String-Objekte.
Das folgende Beispiel erklärt und illustriert diese Aussagen:
• Die Deklaration
String s1;
deklariert eine String-Variable.
• Die Anweisung
new String("Hallo")
erzeugt ein neues String-Objekt.
s1
s1
Hallo
• Die Zuweisung
s1
s1 = new String("Hallo");
Hallo
weist der String-Variablen s1 eine „Referenz“ auf das neu erzeugte Objekt zu. Man sagt dann, dass s1 das Objekt „referenziert“, also
darauf „verweist“, und man kann von s1 aus über die Referenz auf den Inhalt des Objekts
(hier: die String-Konstante "Hallo") zugreifen.
Man muss also klar unterscheiden zwischen String-Objekten, die String-Konstanten speichern, und String-Variablen, in denen Referenzen auf String-Objekte stehen. Diese Unterscheidung ist wichtig bei String-Operationen in Java – insbesondere bei Zuweisungen: Bei
Zuweisungen werden Referenzen, aber keine Objekte kopiert!
• Beispiel: Zuweisung zwischen String-Variablen
s1
s1 = new String("Hallo");
Hallo
s2 = s1;
s2
Bei der Zuweisung wird der Inhalt der Variablen s1
in die Variable s2 kopiert. Da der s1-Inhalt eine Referenz ist, referenziert s2 anschließend
dasselbe Objekt wie s1. Das Objekt selbst wird nicht kopiert, so dass auch nach der Zuweisung nur ein String-Objekt vorhanden ist.
Aufgabe 6: Deklarieren Sie eine String-Variable, erzeugen Sie ein String-Objekt, das Ihren
Namen als Zeichenkette enthält, und lassen Sie die Variable das Objekt referenzieren.
Strings können mit dem +-Operator aneinandergehängt („konkateniert“) werden. Diese Operation haben Sie bereits in println()-Aufrufen gesehen, wo der Ausgabetext durch die Konkatenation von Zeichenketten aufgebaut wurde.
Bei der Anwendung des +-Operators ist relevant, dass String-Objekte nicht „editierbar“ sind,
der Inhalt eines String-Objekts also nicht geändert werden kann. Bei einer Konkatenation
entsteht also ein neues String-Objekt; der Inhalt des vorhandenen Objekts bleibt unverändert.
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
7
• Beispiel: Zuweisung zwischen String-Variablen
Hallo Welt
und anschließende Konkatenation
s1
s1 = new String("Hallo");
Hallo
s2 = s1;
s2
s1 = s1 + new String("Welt");
Nach der Zuweisung s2=s1 referenzieren beide Variablen dasselbe Objekt mit Inhalt
"Hallo" (siehe voriges Beispiel). Durch die anschließende Konkatenation entsteht ein
neues Objekt mit Inhalt "Hallo Welt", das (wegen der Zuweisung s1=...) von s1 referenziert wird. Das bisherige "Hallo"-Objekt bleibt unverändert und wird nach wie vor
von s2 referenziert.
Aufgabe 7: Betrachten Sie die folgende Anweisungsfolge
String a, b, c;
a = new String("Anton");
b = new String("Berta");
c = new String("Cäsar");
a = b;
b = b + new String(" Müller");
Zeichnen Sie eine Skizze, die die String-Variablen und -Objekte sowie die Referenzen in
ihnen zeigt.
Bei der Ausführung von Java-Programmen kommt es oft vor, dass Objekte von keiner Variablen mehr referenziert werden, also nicht mehr zugreifbar sind. Solche Objekte werden durch
das Java-Laufzeitsystem (genauer: den „Java Garbage Collector“) automatisch gelöscht und ihr
Speicherplatz wieder freigegeben; der Programmierer muss sich hierum nicht kümmern,
Die Java-Klasse String definiert eine Reihe nützlicher Methoden zum Umgang mit Zeichenketten. Die folgende Auflistung zeigt einige von ihnen:
• s1.length(): Länge des Strings = Anzahl der Zeichen
• s1.equals(s2): Vergleich zweier Strings (Details dazu siehe unten)
• s1.compareTo(s2): ebenfalls Vergleich zweier Strings (Details dazu siehe unten)
• s1.startsWith("Hal"): Prüfung, ob der String ein bestimmtes Anfangsstück hat
• s1.endsWith("elt"): Prüfung, ob der String ein bestimmtes Endstück hat
• s1.contains("llo"): Prüfung, ob der String einen bestimmten Teilstring enthält
• s1.indexOf("llo"): Position, an der ein bestimmter Teilstring beginnt (wobei die Positionszählung in einem String immer bei 0 beginnt)
• s1.charAt(2): Zeichen, das an einer bestimmten Position des Strings steht
• s1.substring(2): Teilstring, der an einer bestimmten Position des Strings beginnt
Bei der Arbeit mit String-Variablen ist es wichtig, zwischen Vergleichen mit == und Vergleichen mit equals() zu unterscheiden: == vergleicht Referenzen in String-Variablen,
equals() vergleicht String-Konstanten in String-Objekten.
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
8
• Beispiel: Vergleich von Strings.
s1
Hallo
String s1 = new String("Hallo");
String s2 = new String("Hallo");
s2
Hallo
Hier referenzieren s1 und s2 zwei String-Objekte, die
zwar denselben Inhalt haben, aber zwei verschiedene Objekte sind.
s1==s2 vergleicht die Inhalte der String-Variablen (also die Referenzen) und liefert
false, da s1 und s2 verschiedene Objekte referenzieren.
s1.equals(s2) vergleicht die Inhalte der String-Objekte und liefert true, da die Zeichenketten in den Objekten gleich sind.
equals() prüft lediglich, ob zwei Strings gleich oder ungleich sind, und liefert entsprechend
einen boolean-Wert. compareTo() stellt dagegen fest, welcher der beiden Strings gemäß
der „lexikographischen Reihenfolge“ (nach der z.B. Wörter in einem Wörterbuch sortiert sind)
als erster steht. s1.compareTo(s2) liefert eine 0, wenn beide Strings gleich sind, eine negative Zahl, wenn s2 lexikographisch nach s1 steht, und eine positive Zahl sonst.
Aufgabe 8: Welchen Wert liefert der folgende equals()-Aufruf?
String a = "Anton"; ... a.equals("anton");
Aufgabe 9: Laden Sie das Programmbeispiel http://www.nt.th-koeln.de/vogt/dv/java/Daten/
Strings.java herunter, führen Sie es aus und vollziehen Sie seine Operationen im Quellcode nach. Verändern und erweitern Sie es nach Ihren eigenen Ideen.
Aufgabe 10: Gehen Sie zur Online-Dokumentation der Klasse String (http://docs.oracle.com/javase/9/docs/api/ > im linken unteren Fenster "String" suchen und anklicken)
und betrachten Sie die Methoden, die diese Klasse anbietet.
5.4.3. Variablen: Klasse StringBuffer
Neben der Klasse String gibt es in Java die Klasse StringBuffer. StringBuffer-Objekte sind, im Gegensatz zu String-Objekten, „editierbar“; man kann also die Zeichenkette
im Objekt ändern.
Die Klasse StringBuffer definiert einige Methoden, mit denen man auf StringBufferObjekten arbeiten kann. Zwei Beispiele sind die Methoden replace() und reverse():
Mit replace() kann man Teile einer Zeichenkette durch andere Zeichen ersetzen, mit reverse() kann man die gespeicherte Zeichenkette „umdrehen“.
Aufgabe 11: Laden Sie das Programmbeispiel http://www.nt.th-koeln.de/vogt/dv/java/Daten/Stringbuf.java herunter und vollziehen Sie seine Operationen nach. Verändern und
erweitern Sie es nach Ihren eigenen Ideen.
Aufgabe 12: Gehen Sie zur Online-Dokumentation der Klasse StringBuffer (http://docs.oracle.com/javase/9/docs/api/ > im linken unteren Fenster "StringBuffer" anklicken) und betrachten Sie die Methoden, die diese Klasse anbietet.
Aufgabe 13: Laden Sie das Programmbeispiel http://www.nt.th-koeln.de/vogt/dv/java/EinAus/StringEingabe.java herunter. Vollziehen Sie nach, wie das Programm eine Zeichen-
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
9
kette von der Tastatur in ein String-Objekt einliest und wie die Zeichenkette daraus einem
StringBuffer-Objekt zugewiesen wird.
5.5. Lernergebnisse dieses Kapitels
Nach diesem Kapitel muss man mindestens wissen,
• wie die ASCII-Tabelle Zeichen durch Zahlen codiert,
• was der Unterschied zwischen ASCII und Unicode ist,
• warum und wie man mit Zeichen rechnen kann und
• was der Unterschied zwischen Zeichen und Zeichenketten ist.
In Java muss man jetzt mindestens
• Variablen des Typs char deklarieren und initialisieren können,
• Zeichenkonstanten darstellen können,
• zu einem Zeichen das nächste und das vorangehende ermitteln können
• Zeichenketten in String- und StringBuffer-Objekten speichern und verarbeiten können und
• zwischen String-Variablen und String-Objekten unterscheiden können, insbesondere
bei Zuweisungen und Vergleichen.
5.6. Lösung der Aufgaben
Aufgabe 1: 63, 93, _ (Unterstrich), x
Aufgabe 2: Aufgabe 3: char alpha = '\u03B1';
Aufgabe 4: 'h', '=' (nicht 13, denn hier wird nicht mit der Zahl 9, sondern mit dem Unicode/
ASCII-Code des Zeichens '9', also 57 gerechnet)
Aufgabe 5: Aufgabe 6: String ich = new String("Charlie Brown");
Aufgabe 7:
a
Anton
b
Berta
Berta Müller
c
Cäsar
Aufgabe 8: false (denn es wird zwischen Groß- und Kleinbuchstaben unterschieden)
© Prof. C. Vogt, 2017
Verwendung nur mit Quellenangabe
und außerhalb der TH Köln
nur mit Genehmigung des Autors.
Herunterladen