Characters über FFFF

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Characters über FFFF

Beitrag 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?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
DarkSoul
Beiträge: 689
Registriert: 19.10.2006 12:51

Re: Characters über FFFF

Beitrag 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.
Zuletzt geändert von DarkSoul am 16.07.2016 00:15, insgesamt 1-mal geändert.
Bild
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Characters über FFFF

Beitrag 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
DarkSoul
Beiträge: 689
Registriert: 19.10.2006 12:51

Re: Characters über FFFF

Beitrag 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. :)
Bild
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Characters über FFFF

Beitrag von Nino »

@Stargate:
Ich nehme an, dieser Code im engl. Forum hilft Dir weiter.
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Characters über FFFF

Beitrag 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.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Characters über FFFF

Beitrag 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Characters über FFFF

Beitrag von DarkDragon »

STARGÅTE hat geschrieben:Na scheinbar geht es in PureBasic schon, zumindest in der Anzeige.
Hmm seltsam. :? :lol:
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Kukulkan
Beiträge: 1066
Registriert: 09.09.2004 07:07
Wohnort: Süddeutschland
Kontaktdaten:

Re: Characters über FFFF

Beitrag 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
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Characters über FFFF

Beitrag 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten