Es gab - abhängig von Hersteller, Land, Programmiersprache, Betriebsssystem,... - eine große Vielzahl von Codierungen.
Bis heute relevant sind:
Der American Standard Code for Information Interchange wurde 1963 in den USA als Standard veröffentlicht.
definiert $2^7=128$ Zeichen:
newline
, escape
, end of transmission/file
, delete
95 graphisch darstellbare Zeichen:
a-z, A-Z
0-9
.,:;?!"
[{()}]
+-*/<>=
#$%&'\^_|~`@
heute noch "kleinster gemeinsamer Nenner" im Codierungs-Chaos
1987/88 wurden im ISO 8859-Standard verschiedene 1-Byte-Codierungen festgelegt, die alle ASCII-kompatibel sind, darunter:
|Codierung | Region | Sprachen| |:-----------|:----------|:-------| |ISO 8859-1 (Latin-1) | Westeuropa | Deutsch, Französisch,...,Isländisch |ISO 8859-2 (Latin-2) | Osteuropa | slawische Sprachen mit lateinischer Schrift |ISO 8859-3 (Latin-3) | Südeuropa | Türkisch, Maltesisch,... |ISO 8859-4 (Latin-4) | Nordeuropa | Estnisch, Lettisch, Litauisch, Grönländisch, Sami |ISO 8859-5 (Latin/Cyrillic) | Osteuropa | slawische Sprachen mit kyrillischer Schrift |ISO 8859-6 (Latin/Arabic) | | |ISO 8859-7 (Latin/Greek) | | |...| | |ISO 8859-15 (Latin-9)| | 1999: Revision von Latin-1: jetzt mit Euro-Zeichen!
codepoint
zugeordnet. Das ist einfach eine fortlaufende Nummer.Diese Nummer wird hexadezimal notiert
U+XXXX
(0-te Ebene) U+XXXXXX
(weitere Ebenen)U+XY0000
bis U+XYFFFF
, kann also $2^{16}=65\;534$ Zeichen enthalten. XY=00
bis XY=10
, also der Wertebereich von U+0000
bis U+10FFFF
.U+0000 - U+FFFF
,U+010000 - U+01FFFF
,U+020000 - U+02FFFF
, U+030000 - U+03FFFF
undU+0E0000 - U+0EFFFF
vergeben.U+0000
bis U+007F
ist identisch mit ASCIIU+0000
bis U+00FF
ist identisch mit ISO 8859-1 (Latin-1)Im Standard wird jedes Zeichen beschrieben duch
verschiedene Attributen wie
Codepoint und Name:
...
U+0041 LATIN CAPITAL LETTER A
U+0042 LATIN CAPITAL LETTER B
U+0043 LATIN CAPITAL LETTER C
U+0044 LATIN CAPITAL LETTER D
...
U+00E9 LATIN SMALL LETTER E WITH ACUTE
U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX
...
U+0641 ARABIC LETTER FEH
U+0642 ARABIC LETTER QAF
...
U+21B4 RIGHTWARDS ARROW WITH CORNER DOWNWARDS
...
# Wie sieht 'RIGHTWARDS ARROW WITH CORNER DOWNWARDS' aus?
'\U21b4'
'↴': Unicode U+21B4 (category So: Symbol, other)
"""
printuc(c, n):
print n characters from unicode table, starting with character c
"""
function printuc(c, n)
for i in 0:n-1
print(c + i)
end
end
printuc
Kyrillisch
printuc('\U0400', 100)
ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣ
Tamilisch
printuc('\U0be7',20)
௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺
Schach
printuc('\U2654', 12)
♔♕♖♗♘♙♚♛♜♝♞♟
mathematische Operatoren
printuc('\U2200', 255)
∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾
Runen
printuc('\U16a0', 40)
ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇ
Scheibe (Diskus) von Phaistos
printuc('\U101D0', 46 )
𐇐𐇑𐇒𐇓𐇔𐇕𐇖𐇗𐇘𐇙𐇚𐇛𐇜𐇝𐇞𐇟𐇠𐇡𐇢𐇣𐇤𐇥𐇦𐇧𐇨𐇩𐇪𐇫𐇬𐇭𐇮𐇯𐇰𐇱𐇲𐇳𐇴𐇵𐇶𐇷𐇸𐇹𐇺𐇻𐇼𐇽
Unicode transformation formats legen fest, wie eine Folge von Codepoints als eine Folge von Bytes dargestellt wird.
Da die Codepoints unterschiedlich lang sind, kann man sie nicht einfach hintereinander schreiben. Wo hört einer auf und fängt der nächste an?
UTF-32: Das einfachste, aber auch speicheraufwändigste, ist, sie alle auf gleiche Länge zu bringen. Jeder Codepoint wird in 4 Bytes = 32 Bit kodiert.
Bei UTF-16 wird ein Codepoint entweder mit 2 Bytes oder mit 4 Bytes dargestellt.
Bei UTF-8 wird ein Codepoint mit 1,2,3 oder 4 Bytes dargestellt.
UTF-8 ist das Format mit der höchsten Verbreitung. Es wird auch von Julia verwendet.
Bei einer Codierung mit variabler Länge muss man erkennen können, welche Bytefolgen zusammengehören:
Damit ist der Platz, der für den Codepoint zur Verfügung steht (Anzahl der x):
Damit ist jeder ASCII-Text automatisch auch ein korrekt codierter UTF-8-Text.
Sollten die bisher für Unicode festgelegten 17 Ebenen = 21 Bit = 1.1 Mill. mögliche Zeichen mal erweitert werden, dann wird UTF-8 auf 5- und 6-Byte-Codes erweitert.
Char
¶'a'
UInt
s umgewandelt werdenString
¶"a"
@show typeof('a') sizeof('a') typeof("a") sizeof("a");
typeof('a') = Char sizeof('a') = 4 typeof("a") = String sizeof("a") = 1
UInt('a')
0x0000000000000061
b = Char(0x2656)
'♖': Unicode U+2656 (category So: Symbol, other)
Bei einem Nicht-ASCII-String unterscheiden sich Anzahl der Bytes und Anzahl der Zeichen:
astr = "Hello World!"
@show length(astr) ncodeunits(astr);
length(astr) = 12 ncodeunits(astr) = 12
str = "😄 Hellö 🎶"
@show length(str) ncodeunits(str);
length(str) = 9 ncodeunits(str) = 16
Iteration über einen String iteriert über die Zeichen:
for i in str
println(i, " ", typeof(i))
end
😄 Char Char H Char e Char l Char l Char ö Char Char 🎶 Char
"Strings mit Verkettung bilden ein nichtkommutatives Monoid."
str * astr * str
"😄 Hellö 🎶Hello World!😄 Hellö 🎶"
str^3
"😄 Hellö 🎶😄 Hellö 🎶😄 Hellö 🎶"
wird oft in print() usw. genutzt
a = 33.4
b = "x"
s = "Das Ergebnis für $b ist gleich: $a\n"
"Das Ergebnis für x ist gleich: 33.4\n"
Julia benutzt die von C und anderen Sprachen bekannten backslash-Codierungen:
s = "So bekommt man \'Anführungszeichen\" und ein \$-Zeichen und einen\nZeilenumbruch und ein \\ usw... "
print(s)
So bekommt man 'Anführungszeichen" und ein $-Zeichen und einen Zeilenumbruch und ein \ usw...
In dieser Form bleiben Zeilenumbrüche und Anführungszeichen erhalten:
s = """
Das soll
ein "längerer"
'Text' sein.
"""
print(s)
Das soll ein "längerer" 'Text' sein.
In einem raw string
sind alle backslash-Codierungen ausser \"
abgeschaltet:
s = raw"Ein $ und ein \ und zwei \\ und ein 'bla'..."
print(s)
Ein $ und ein \ und zwei \\ und ein 'bla'...
@show isdigit('0') isletter('Ψ') isascii('\U2655') islowercase('α') isnumeric('½') iscntrl('\n') ispunct(';');
isdigit('0') = true isletter('Ψ') = true isascii('♕') = false islowercase('α') = true isnumeric('½') = true iscntrl('\n') = true ispunct(';') = true
Diese Tests lassen sich z.B. mit all()
, any()
oder count()
auf Strings anwenden:
all(ispunct, ";.:")
true
any(isdigit,"Es ist 3 Uhr! 🕒" )
true
count(islowercase,"Hello, du!!")
6
@show startswith("Lampenschirm", "Lamp") occursin("pensch", "Lampenschirm") endswith("Lampenschirm", "irm");
startswith("Lampenschirm", "Lamp") = true occursin("pensch", "Lampenschirm") = true endswith("Lampenschirm", "irm") = true
@show uppercase("Eis") lowercase("Eis") titlecase("eiSen");
uppercase("Eis") = "EIS" lowercase("Eis") = "eis" titlecase("eiSen") = "Eisen"
# remove newline from end of string
@show chomp("Eis\n") chomp("Eis");
chomp("Eis\n") = "Eis" chomp("Eis") = "Eis"
split("π ist irrational.")
3-element Vector{SubString{String}}: "π" "ist" "irrational."
replace("π ist irrational.", "ist" => "ist angeblich")
"π ist angeblich irrational."
Besonderheiten:
str
"😄 Hellö 🎶"
# das erste Zeichen
str[1]
'😄': Unicode U+1F604 (category So: Symbol, other)
# da es 4 bytes lang ist, sind 2,3,4 alles ungültige Indizes:
str[2]
StringIndexError: invalid index [2], valid nearby indices [1]=>'😄', [5]=>' ' Stacktrace: [1] string_index_err(s::String, i::Int64) @ Base ./strings/string.jl:12 [2] getindex_continued(s::String, i::Int64, u::UInt32) @ Base ./strings/string.jl:233 [3] getindex(s::String, i::Int64) @ Base ./strings/string.jl:226 [4] top-level scope @ In[32]:3 [5] eval @ ./boot.jl:373 [inlined] [6] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1196
# erst das 5. Byte ist ein neues Zeichen:
str[5]
' ': ASCII/Unicode U+0020 (category Zs: Separator, space)
# auch bei der Adressierung von Substrings müssen Anfang und Ende
# jeweils gültige Indizes sein
str[1:7]
"😄 He"
# eachindex() liefert einen Iterator über die gültigen Indizes:
for i in eachindex(str)
c = str[i]
println("$i: $c")
end
1: 😄 5: 6: H 7: e 8: l 9: l 10: ö 12: 13: 🎶
# ... und wie üblich macht collect() aus einem Iterator einen Vektor:
collect(eachindex(str))
9-element Vector{Int64}: 1 5 6 7 8 9 10 12 13
# und nextind() liefert den nächsten gültigen Index
@show nextind(str, 1) nextind(str, 2);
nextind(str, 1) = 5 nextind(str, 2) = 5
Warum? Effizienz!
s[123455]
mit einem Byte-Index schnell zu finden. Einige Funktionen liefern Indizes oder Ranges als Resultat. Sie liefern immer gültige Indizes:
findfirst('l', str)
8
findfirst("Hel", str)
6:8
str2 = "αβγδϵ"^3
"αβγδϵαβγδϵαβγδϵ"
n = findfirst('γ', str2)
5
# Weitersuchen ab dem nächsten nach n=5 gültigen Index:
findnext('γ',str2, nextind(str2, n))
15