Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Unicode strings (https://www.delphipraxis.net/181351-unicode-strings.html)

eric_draven 8. Aug 2014 10:16

Unicode strings
 
Hallo,

in einigen Projekten (Delphi7-2005) benutze ich strings für hardwarenahe Kommunikation. Dies hat für mich einige Vorteile gegenüber z.B. Byte Arrays, da Teilstrings als Konstanten hinterlegt werden können oder mal eben testweise schnell eingegeben, etc.
Leider führt dies durch Unicode in neuer Versionen zu Problemen, da ich bisher keinen reinen ByteString Typ gefunden hab.
Beispiel:
bisher:

...
...Send(HEADER + #$01#$02 + 'abc' + #12 + Data);
...

Hat jemand eine Idee, wie ich das mit einer aktuellen Delphi Version (XEn) ähnlich umsetzen kann ? Mit RawByteString, Codepages, etc. hatte ich bisher keinen Erfolg.

mkinzler 8. Aug 2014 10:17

AW: Unicode strings
 
Funktioniert AnsiString?

Der schöne Günther 8. Aug 2014 10:25

AW: Unicode strings
 
RawByteString ist doch nur ein Alias für AnsiString?

Wobei mich das wundert. Ich dachte AnsiString ist in neueren Versionen genau das, was in füheren Versionen String war?

mjustin 8. Aug 2014 10:58

AW: Unicode strings
 
Zitat:

Zitat von eric_draven (Beitrag 1267966)
mit RawByteString ... hatte ich bisher keinen Erfolg.

Dann wurde der RawByteString wahrscheinlich irgendwo klammheimlich wieder in einen Unicodestring konvertiert, zum Beispiel bei einer Stringverkettung oder einem Methodenaufruf. Der Compiler zeigt dann aber normalerweise eine Warnung an.

p80286 8. Aug 2014 12:51

AW: Unicode strings
 
U.U mußt Du auch auf die "ganz alten" Strings (ShortStrings)
Delphi-Quellcode:
MeinString : string[255];
zurückgreifen. Aber mit ANSI..... liegst Du erst mal nicht falsch.

Gruß
K-H

himitsu 8. Aug 2014 13:04

AW: Unicode strings
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1267969)
RawByteString ist doch nur ein Alias für AnsiString?

Wobei mich das wundert. Ich dachte AnsiString ist in neueren Versionen genau das, was in füheren Versionen String war?

String war früher ein Alias für den AnsiString
und jetzt ist es ein Alias für den UnicodeString.
Genauso, wie früher (vor Win64) der Integer ein Alias für den LongInt (Win32) und davor für den SmallInt (Win16) war, also das, was jetzt der NativeInt ist, da man bescheuerter Weise den Integer eingefrohren hat. (aus Angst vor Problemen bei der Umstellung auf 64 Bit, aufgrund von schrottig programmierten Codes)

Ein AnsiString ist mit der akuellen Codepage des Systems/Programms (CP_ACP),
RawByteString ist ein AnsiString ohne CodePage,
UTF8String ist ein AnsiString mit der CodePage CP_UTF8
und AnsiString(123) hat die CodePage 123.
Der ShortString ist immer CP_ACP. (das ist ein Rerord und kein Long-String, so wie UnicodeString, AnsiString und Co.)

Und ja, Delphi konvertiert die Strings untereinander.
Wenn man einen UnicodeString an einen UTF8String übergibt, dann wird der Inhalt nach UTF-8 konvertiert, also anhand der CodePage des AnsiString.
Umgekehrt genauso.

Darum gibt es auch den RawByteString, da dieser die "ANSI"-Zeichen, im unteren Byte-Bereich (0 bis 255) des Unicode 1:1 kopiert, ohne zu übersetzen.

Patito 8. Aug 2014 13:34

AW: Unicode strings
 
Zitat:

Zitat von eric_draven (Beitrag 1267966)
Hallo,

in einigen Projekten (Delphi7-2005) benutze ich strings für hardwarenahe Kommunikation. Dies hat für mich einige Vorteile gegenüber z.B. Byte Arrays, da Teilstrings als Konstanten hinterlegt werden können oder mal eben testweise schnell eingegeben, etc.
Leider führt dies durch Unicode in neuer Versionen zu Problemen, da ich bisher keinen reinen ByteString Typ gefunden hab.
Beispiel:
bisher:

...
...Send(HEADER + #$01#$02 + 'abc' + #12 + Data);
...

Hat jemand eine Idee, wie ich das mit einer aktuellen Delphi Version (XEn) ähnlich umsetzen kann ? Mit RawByteString, Codepages, etc. hatte ich bisher keinen Erfolg.

Als ich früher solche Fragen gestellt habe, lagen die Statements von diversen Delphi-Leuten
irgendwo zwischen "So etwas sollte man nicht machen" und grobem Unverständnis.

Ein Problem hier kann z.B. sein, dass Konstanten wie #$01 nich das liefern, was Du erwartest.
So etwas wird schon mal stillschweigend in andere Char-Codierungen umgewandelt.

Mein Tip: Mach einen Bogen um die XEs.

Mit etwas Geduld und Gewalt kriegt man soetwas bestimmt irgendwie hin. Aber Arbeitszeit aufzuwenden um die ganzen
Absonderlichkeiten von einem Tool zu verstehen, dessen Entwickler es für eine tolle Idee halten den Support für
AnsiStrings einzuschränken (bzw. planen ihn in Zukunft auch mal ganz zu entfernen) ist einfach nicht sinnvoll.

himitsu 8. Aug 2014 14:03

AW: Unicode strings
 
#$01 entspricht dem #1 und alles im ASCII-Bereich (#0 bis #127) ist in allen Kodierungen gleich, womit das niemals eine Veränderung erfahren sollte.
Die #0 muß zwar beachtet werden, aber der String selber kann solche Zeichen problemlos behandeln, solange man nicht fahrlässig mit PChar-Funktionen, ohne Längenangabe, rumhantiert.

Wie ist denn das Send deklaiert? (mit String-Parameter?)


Wo man etwas aufpassen muß, ist z.B. bei #$0085 und #$85 oder #133, denn bei Erstem geht Delphi davon aus, daß es Unicode ist und beim Letzen kann es als ANSI behandelt werden und erfährt dann eventuell eine Konvertierung nach Unicode.
Rein logisch ist es zwar das Selbe, aber der Compiler achtet halt auf sowas.



Aus soeinem Grund hab ich grade eine Serial-Port-Komponente komplett neu aufgesetzt, bzw. bin noch dabei.
Die ist von der Schnittstelle der vom C# ähnlich, mit Anpassungen an Delphi und diese String-Probleme, einer internen explizit steuerbaren String-Konvertierung und mit Erweiterungen anhand der zusätzlichen Möglichkeiten der WinAPI. (und später hoffentlich auch noch für iOS und vorallem für Android)
Wobei ich absichtlich auch TBytes unterstütze, um das String-Konvertierungs-Problem ganz auszuschließen.

Wobei iOS/Android noch Spaß machen wird, denn dort gibt es keinen AnsiString mehr ... nur noch Unicode.

eric_draven 8. Aug 2014 14:37

AW: Unicode strings
 
hmmm, AnsiStrings, Codepages, Shortstrings hatte ich schon alles probiert. Das mit dem RawByteString hört sich gut an, funktioniert aber immer noch nicht :cry: . Alles was grösser Ord(127) ist, wird in irgendeinen sinnlosen Wert gewandelt, z.B. $ff => $3f.
Im diesem konkreten Beispiel rufe ich die UDPClient.Send Funktion von Indy auf, wenn man diese verfolgt, sieht die so aus:
Code:
procedure TIdUDPClient.Send(const AData: string; AByteEncoding: IIdTextEncoding = nil
  {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
  );
begin
  Send(Host, Port, AData, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF});
end;
Pseudo-Aufruf:
UDPClient.Send(RawByteString(....));
Also Encoding = nil

eric_draven 8. Aug 2014 14:41

AW: Unicode strings
 
ah, Himitsu, Du hast mittlerweile nochmal geschrieben. Genau so ist es, 0..127 alles OK, darüber = blödsinn.
Die Bytes sind immer als zweier hex komplementäre geschrieben, z.B. #$00, #$FF, ...

himitsu 8. Aug 2014 14:47

AW: Unicode strings
 
Entweder du benutzt einen Send-Befehl, welcher keinen String verwendet.
=> Buffer (VAR ohne Typ), TBytes, einen TStream oder einzeln Byte für Byte

Oder du speicherst deinen Text in einem AnsiString.
Bei Übergabe wird der dann nach Unicode konvertiert und vom IdTextEncoding, hoffentlich mit der richtigen CodePage (0 = CP_ACP) wieder in zurück Ansi,
wobei dann hoffentlich alle Bytes wieder so sind, wie sie waren/sollen.

Oder du probierst es mit einem RawByteString. Vor Übergabe sicherheitshalber nochmal mit Delphi-Referenz durchsuchenSetCodePage die CodePage auf $ffff setzen.
Und dann beim Senden ein IIdTextEncoding mit der CodePage $ffff verwenden. (ich hoffe die können damit umgehen)

Whookie 8. Aug 2014 17:34

AW: Unicode strings
 
Ich habe auch eine uralte serielle Library beim Umstieg auf Delphi XE konvertiert und intern dafür AnsiString/AnsiChar/PAnsiChar verwendet, was ohne großen Aufwand über die Bühne ging (konvertieren auf TBytes hätte eine Menge mehr Arbeit bedeutet). Bei mir geht das problemlos weil intern Strings verwendet werden von außen aber Daten (Bytes/Word/DWord/Float) angeliefert werden.

Dein Problem liegt aber wohl darin, dass du diese Trennung nicht machen kannst weil du direkt im Programm mit den Strings arbeitest. Aus meiner Sicht gibts daher nur zwei Möglichkeiten:

1. Hardcast über AnsiString und AnsiChar für alles was mit dem Protokoll zu tun hat:

Code:
Const
  ETX = AnsiChar(2); //stellvertretend für alle Steuercodes....
  CHeader: AnsiString = #230'vorne'#231;

procedure TForm4.Button1Click(Sender: TObject);
Var
  Header: AnsiString;
begin
  Send(CHeader+AnsiString('Meine Daten'#$F3#$EE'hinten')+ETX);
end;


procedure TForm4.Send(AString: AnsiString);
begin
  //hier sollte alles passen
end;
2. Konvertieren vor dem Senden.
Das ist einwenig "riskant", abhängig von den Daten (siehe weiter unten)

Code:
Const
  ETXu = #2;
  CHeaderu = #230'vorne'#231;


procedure TForm4.Button2Click(Sender: TObject);
Var
  Header: String;
begin
  Sendu(CHeader+'Meine Daten'#$F3#$EE'hinten'+ETX)
end;

procedure TForm4.Sendu(AString: String);
Var
  iSend: AnsiString;
  i: Integer; // könnte auch TByte sein...
begin
  // konvertieren in AnsiString
  SetLength(iSend, Length(AString));
  for i := 0 to Length(AString) do
  begin
    iSend[i] := AnsiChar(AString[i]);
  end;
  // jetzt kann iSend übertragen werden...
end;
Probleme bringt diese Version immer dann wenn du Zeichen ausserhalb des Ansi-Bereichs senden möchtest also etwa:

Code:
CHeaderu='öÖäß...'
denn in deinem Code darfst du nur Zeichen bis 127 zwischen den Anführungszeichen verwenden, alles andere muss in der Form #xxx angegeben werden. Auch eine Wandlung von Unicode nach Ansi ist in Sendu() nicht möglich.

Bernhard Geyer 8. Aug 2014 22:07

AW: Unicode strings
 
Zitat:

Zitat von Patito (Beitrag 1268020)
Als ich früher solche Fragen gestellt habe, lagen die Statements von diversen Delphi-Leuten
irgendwo zwischen "So etwas sollte man nicht machen" und grobem Unverständnis.

So wie oben macht man es ja auch nicht. Hier wäre sinnvoll das was man als OSI-Modell kennt auch entsprechend auf Klassen aufzuteilen und nicht den ganzen Packetaufbau so zusammenzufassen.
Hat man entsprechende Klassen/Helperunits muss man sich um Charactercodierung nur an wenigen Stellen Quellcode Gedanken machen.

Zitat:

Zitat von Patito (Beitrag 1268020)
Ein Problem hier kann z.B. sein, dass Konstanten wie #$01 nich das liefern, was Du erwartest.
So etwas wird schon mal stillschweigend in andere Char-Codierungen umgewandelt.

Eigentlich nicht. $01 ist immer $01. Egal welche Codierung. Jedoch kann es sein wenn man sowas an WinAPI-Funktionen übergibt die Strings erwarten das hier diese Sonderzeichen verstümmelt werden weil die Funktion nur Druckbare Zeichen erwartet. Hatte erst vor kurzen den Fall das ein Unicodezeichen kein richtiges Zeichen war und UTF8-Codiert eine defekte XML-Datei produziert hatte.

Zitat:

Zitat von Patito (Beitrag 1268020)
Mein Tip: Mach einen Bogen um die XEs.

Mein Tipp. Ist nicht nötig. Die XEs sind sehr gut zu verwenden.

Zitat:

Zitat von Patito (Beitrag 1268020)
Mit etwas Geduld und Gewalt kriegt man soetwas bestimmt irgendwie hin.

Da braucht man keine Gewalt. Man muss nur verstehen wie Strings Funktionieren und schon funktioniert es in 99% aller Fälle auf Anhieb.

Zitat:

Zitat von Patito (Beitrag 1268020)
Aber Arbeitszeit aufzuwenden um die ganzen Absonderlichkeiten von einem Tool zu verstehen,
dessen Entwickler es für eine tolle Idee halten den Support für AnsiStrings einzuschränken
(bzw. planen ihn in Zukunft auch mal ganz zu entfernen) ist einfach nicht sinnvoll.

Wenn Du meinst. Man brauche eigentlich in 99% der Fälle keine AnsiStrings. Man muss nur Wissen wie man Daten einlist (Stichworte BOM, Konvertierungsfunktionen, ...) und wie man Sie ausgibt.
Glücklicherweise hat Emba/Delphi den Weg genommen mit Unicodestrings zu arbeiten statt hier eine Krückenlösung ala FreePascal mit UTF8 zu realisieren.
Da wo man sich Delphi XEx keine Gedanken mehr machen muss bezüglich Dateizugriff und Sonderzeichen in Dateinamen, muss man bei Freepascal noch überlegen ob man nun die Funktion mit oder ohne UTF8/native im Namen verwendet.

p80286 9. Aug 2014 00:48

AW: Unicode strings
 
Zitat:

Zitat von Patito (Beitrag 1268020)
Als ich früher solche Fragen gestellt habe, lagen die Statements von diversen Delphi-Leuten
irgendwo zwischen "So etwas sollte man nicht machen" und grobem Unverständnis.

Das kannst Du gerne haben. Char/String ist im 8-Bit Bereich oft eine Frage der Interpretation, einzig 0..9,A..Z und a..z und das Blank sind überall (soweit ich weiß) gleich. Sonderzeichen und Umlaute sind mehr oder weniger frei verteilt, ganz zu schweigen von den TTY-Steuerzeichen. Wenn man schon mit Char/String arbeiten will/muß dann sollte man schon wissen, was die Umgebungsvariablen (Codepage, Zeichensatz, Font) sind. Im Zweifel sollten immer numerische Werte (Byte) übergeben werden. Nicht umsonst werden z.B. die PCL-Steuersequenzen als Byte-Folgen angegeben.

Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz