Seite 1 von 2

Characters über FFFF

Verfasst: 15.07.2016 23:26
von STARGÅTE
Hallo,

ich bin gerade etwas verwundert, bzw. stellen sich mir einige Fragen, wie PureBasic mit Zeichen über FFFF umgeht.
Da der Ascii-Support eingestellt wurde, wollte ich mal in die andere Richtung blicken.

Die folgenden Zeichen gehören zu Mathematical Alphanumeric Symbols (1D400—1D7FF).

In PureBasic werden diese Zeichen auch korrekt dargestellt, wenn die als String definiert werden:

Code: Alles auswählen

Enumeration
	#Window
	#Gadget
	#Font
EndEnumeration

OpenWindow(#Window, 0, 0, 800, 600, "WindowTitle", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))

LoadFont(#Font, "Cambria Math", 20)

Define String.s = PeekS(?String)
ShowMemoryViewer(@String, StringByteLength(String))
If StartVectorDrawing(CanvasVectorOutput(#Gadget))
	VectorFont(FontID(#Font), 40)
	DrawVectorText(String)
	StopVectorDrawing()
EndIf

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

DataSection
	String:
	Data.l -581773259, -581707723, -581642187, -581576651, -581511115, -581445579, -581380043, -581314507
	Data.l -581248971, -581183435, -581117899, -581052363, -580986827, -580921291, -580855755, -580790219
	Data.l -580724683, -580659147, -580593611, -580528075, -580462539, -580397003, -580331467, -580265931
	Data.l -580200395, -580134859, 0
EndDataSection
(Selbst das Board streikt, diese Zeichen als Klartext in die Datenbank einzugeben^^)

Allerdings scheinen das nicht alle Funktionen mit zu machen:

Code: Alles auswählen

Define String.s = PeekS(?String)

Debug "Länge:  "+Str(Len(String))+"  (ich hätte hier 26 erwartet)" 
Debug "Bytes:  "+Str(StringByteLength(String))+"  (richtig)"
Debug "Nummer: "+Hex(Asc(PeekS(?String, 4)))+" (sollte 1D552 sein oder zumindest DD52D835, was ja UTF-16 LE wäre)"

DataSection
	String:
	Data.l -581773259, -581707723, -581642187, -581576651, -581511115, -581445579, -581380043, -581314507
	Data.l -581248971, -581183435, -581117899, -581052363, -580986827, -580921291, -580855755, -580790219
	Data.l -580724683, -580659147, -580593611, -580528075, -580462539, -580397003, -580331467, -580265931
	Data.l -580200395, -580134859, 0
EndDataSection
Auch wie man solche Zeichen mit Chr() erzeugt ist mir nicht klar.
Kann mir hier vielleicht weitere Informationen geben?

Re: Characters über FFFF

Verfasst: 16.07.2016 00:01
von DarkSoul
Ich habe sowas ähnliches letztens hier gefragt, nämlich, welche Codierung PB eigentlich verwendet, wenn man #PB_Unicode verwendet. Es ist UCS-2 und dieser Standard kann nur den Zeichenbereich 0000h-FFFFh abbilden. Alles darüber kann nicht abgebildet werden und ist somit nicht verwendbar.

Ein UCS-2-Zeichen hat nur zwei Byte. Dein Data-Block enthält Long-Werte. Diese sind allerdings 4 Byte lang. Was du somit im Data-Block vorhältst, wäre UCS-4. Daher wird ein Long-Wert als 2 Zeichen missinterpretiert, denn PB sieht nur die Bytes und kann den Fehler nicht erkennen. Der gültige Zahlenbereich wäre hier 0-65535 unter Verwendung von 2-Byte großen Words.

Aus diesem Grund ist dein String nun auch doppelt so lang (aber im RAM immer noch gleich lang, weil 104 Bytes bleiben 104 Bytes, egal, ob als Long oder Word interpretiert)

Also: Dicke Backen machen oder mit Speicherbereichen+Poinern arbeiten und UCS-4 (Das ist das Format deiner DataSection) verwenden, wenn du es wirklich brauchst. Werde kreativ. :twisted:

Folgendes ohne Garantie:
Ich glaube, dass UTF8 so hoch abbilden kann, weil es variabel ist. Ich weiß allerdings nicht, ob PB das auch kann, weil die Strings intern trotzdem in UCS-2 sind und diese bei Bedarf in UTF8 codiert werden.

PS: In ASCII kannst du das erst recht nicht codieren. Kann somit auch vorher nicht funktioniert haben. ASCII hat einen Wertebereich von 0-255, von denen allerdings nur die ersten 127 auf allen Computern einheitlich sind. Alles darüber ist länderspezifisch und von der im Computer eingestellten Codepage abhängig.

Re: Characters über FFFF

Verfasst: 16.07.2016 00:12
von STARGÅTE
@DarkSoul:

Genau.
Laut Wiki (Quelle) ist im UTF-16 oder UCS-2 Format ein Bereich definiert, der ähnlich wie in UTF8 signalisiert, dass das Zeichen aus 4 Byte statt nur 2 Bytes besteht.

Ein kompatibles Chr() sieht dann so aus:

Code: Alles auswählen

Procedure.s UnicodeChr(Number.i)
	Protected Buffer.q
	If Number <= $FFFF
		Buffer = Number
		ProcedureReturn PeekS(@Buffer, -1, #PB_Unicode)
	Else
		Buffer = (Number-$10000)>>10 | ((Number-$10000)&$3FF)<<16 + $DC00D800
		ProcedureReturn PeekS(@Buffer, -1, #PB_Unicode)
	EndIf
EndProcedure

MessageRequester("U+1D4D7", UnicodeChr($1D4D7))
was erst mal zu funktionieren scheint.

Re: Characters über FFFF

Verfasst: 16.07.2016 00:23
von DarkSoul
Sind UTF-16 und UCS-2 nicht zwei verschiedene Codierungen? Ich meine nämlich zu glauben, dass das bei UTF-16 geht und bei UCS-2 nicht. :shock:

PS: Bei mir wirds auch richtig dargestellt. Aber ist trotzdem gefährlich:

Füge mal diese Codezeile ein und staune. Das Ergebnis ist 2. Es ist aber nur ein Character :mrgreen: .
Debug Len(UnicodeChr($1D4D7))
Vermutlich nutzt PB intern wirklich UCS-2, aber die WinAPI interpretiert das als UTF16. :)

Re: Characters über FFFF

Verfasst: 16.07.2016 12:22
von Nino
@Stargate:
Ich nehme an, dieser Code im engl. Forum hilft Dir weiter.

Re: Characters über FFFF

Verfasst: 17.07.2016 10:22
von DarkDragon
PureBasic lässt das meiner Erinnerung nach nicht zu und implementiert lediglich wide chars wie von Microsoft vorgesehen: https://msdn.microsoft.com/en-us/library/z207t55f.aspx

Allerdings zeigt der von Nino verlinkte und von Demivec geschriebene Code, wie man von UTF-16 zu diesen widechars kommt und umgekehrt. Allerdings wird es dann immernoch das Problem mit der Anzeige geben, sofern man das will.

Re: Characters über FFFF

Verfasst: 17.07.2016 13:31
von STARGÅTE
Na scheinbar geht es in PureBasic schon, zumindest in der Anzeige.
Nur die implimentierten Funktionen machen das nicht direkt mit.
Daher schreib ich mir gerade ein paar Ersatzfunktionen, so wie es Nino schon verlinkt hat, nur das ich auch Sachen wie Len(), Mid(), Left(), Right() anpassen muss.

Re: Characters über FFFF

Verfasst: 17.07.2016 14:54
von DarkDragon
STARGÅTE hat geschrieben:Na scheinbar geht es in PureBasic schon, zumindest in der Anzeige.
Hmm seltsam. :? :lol:

Re: Characters über FFFF

Verfasst: 03.05.2017 17:12
von Kukulkan
STARGÅTE hat geschrieben:Nur die implimentierten Funktionen machen das nicht direkt mit.
Daher schreib ich mir gerade ein paar Ersatzfunktionen, so wie es Nino schon verlinkt hat, nur das ich auch Sachen wie Len(), Mid(), Left(), Right() anpassen muss.
Hallo STARGÅTE,

hast Du inzwischen, neben Chr() und Asc(), weitere Funktionen auf UTF16 angepasst? Wärst Du bereit diese hier zu posten? Ich habe die Aufgabe demnächst vieles auf Chinesisch zu übersetzen und da wäre das vermutlich recht hilfreich.

Danke,

Kukulkan

Re: Characters über FFFF

Verfasst: 03.05.2017 23:21
von STARGÅTE
Hallo Kukulkan,

ich hatte den Code nie ausführlich getestet, aber hier mal ein paar Prozeduren:

Code: Alles auswählen

Structure Surrogate
	StructureUnion
		High.u
		Character.u
	EndStructureUnion
	Low.u
EndStructure

Procedure.s UnicodeChr(Number.i)
	Protected Buffer.l
	If Number <= $FFFF
		ProcedureReturn Chr(Number)
	Else
		Buffer = (Number&$3FF)<<16 | (Number-$10000)>>10 | $DC00D800
		ProcedureReturn PeekS(@Buffer, 2, #PB_Unicode)
	EndIf
EndProcedure

Procedure.i UnicodeAsc(String.s)
	Protected *Buffer.Surrogate = @String
	If *Buffer\High & $FC00 = $D800 And *Buffer\Low & $FC00 = $DC00
		ProcedureReturn (*Buffer\High&$3FF)<<10 | (*Buffer\Low&$3FF) + $10000
	Else
		ProcedureReturn Asc(String)
	EndIf
EndProcedure

Procedure.i UnicodeLen(String.s)
	Protected *Buffer.Surrogate = @String
	Protected Count.i = 0
	If *Buffer
		While *Buffer\Character
			Count + 1
			If *Buffer\High & $FC00 = $D800 And *Buffer\Low & $FC00 = $DC00
				*Buffer + SizeOf(Surrogate)
			Else
				*Buffer + SizeOf(Unicode)
			EndIf
		Wend
	EndIf
	ProcedureReturn Count
EndProcedure

Procedure.s UnicodeMid(String.s, Start.i, Length.i=-1)
	Protected *Buffer.Surrogate = @String
	Protected *Offset, Count.i = 0
	If *Buffer
		While *Buffer\Character And Start > 1
			Start - 1
			If *Buffer\High & $FC00 = $D800 And *Buffer\Low & $FC00 = $DC00
				*Buffer + SizeOf(Surrogate)
			Else
				*Buffer + SizeOf(Unicode)
			EndIf
		Wend
		*Offset = *Buffer
		If Length = -1
			ProcedureReturn PeekS(*Offset, -1, #PB_Unicode)
		ElseIf Length > 0
			While *Buffer\Character And Length > 0
				Length - 1
				If *Buffer\High & $FC00 = $D800 And *Buffer\Low & $FC00 = $DC00
					*Buffer + SizeOf(Surrogate)
				Else
					*Buffer + SizeOf(Unicode)
				EndIf
			Wend
			ProcedureReturn PeekS(*Offset, (*Buffer-*Offset)>>1, #PB_Unicode)
		EndIf
	EndIf
	ProcedureReturn ""
EndProcedure

Procedure.s UnicodeLeft(String.s, Length.i)
	ProcedureReturn UnicodeMid(String, 0, Length)
EndProcedure

Procedure.s UnicodeRight(String.s, Length.i)
	ProcedureReturn UnicodeMid(String, UnicodeLen(String)-Length+1, Length)
EndProcedure




Define MyString.s = "H"+UnicodeChr($1D4D7)+"ℍ"+UnicodeChr($1D573)

Debug MyString

Debug "Asc: " + Hex(UnicodeAsc(UnicodeChr($1D4D7))) + " should be 1D4D7"

Debug "Len: " + Str(UnicodeLen(MyString)) + " should be 4"

Debug "Mid: " + UnicodeMid(MyString, 2, 2) + " should be "+UnicodeChr($1D4D7)+"ℍ"

Debug "Left: " + UnicodeLeft(MyString, 2) + " should be "+"H"+UnicodeChr($1D4D7)

Debug "Right: " + UnicodeRight(MyString, 2) + " should be "+"ℍ"+UnicodeChr($1D573)



Enumeration
   #Window
   #Gadget
   #Font
EndEnumeration

OpenWindow(#Window, 0, 0, 200, 200, "WindowTitle", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))
LoadFont(#Font, "Cambria Math", 20)

If StartVectorDrawing(CanvasVectorOutput(#Gadget))
   VectorFont(FontID(#Font), 50)
   MovePathCursor(20, 0)
   DrawVectorText(MyString)
   StopVectorDrawing()
EndIf

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Falls noch was notwendig ist, kann ich es gerne noch ergänzen.