Entwickler-Ecke

Sonstiges (Delphi) - ä, ö, üs in ACII geht nicht!?


Killi - Fr 24.10.03 15:12
Titel: ä, ö, üs in ACII geht nicht!?
Hi!

Es geht um folgendes problem: Ich lese eine Krankenkassenkarte mit TSmartCard aus, Beispiel-Code war dabei, damit kann ich nix anfangen, habe es eben drin gelassen - Daten werden auch wunderbar gelesen, allerdings gibt es auch Karten auf denen der Name mit Umlauten, also ä,ö und üs geschrieben wird - hier bekomme ich nur ein "{"...wie kann ich das verhindern? Liegt es etwa daran (?):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
procedure TFKarte.ExecSCardCmd(Cmd,DataIn: String);
const BufferSize = 32768;
var P,pDataIn: PChar;
    DataASCII, DataHex, DataInHex: String;
    C: Integer;
    Len, LenIn: LongInt;
begin
  MemoDataOut.Clear;
  if (Cmd = ''then begin
    MemoDataOut.Lines.Add('no command');
    exit;
  end;
  with EditDataIn do if ((Font.Color=clRed) and (Text='(nil)')) then DataIn:='';
  ShowCommand(Cmd,DataIn);
  P:=AllocMem(BufferSize);
  if DataIn='' then begin pDataIn:=nil; LenIn:=0end else begin
    if RadioButtonHEX.Checked then begin
      (* DataIn can either be in ASCII or in HEX, depending on the
         seleced RadioButton. If we have a HEX string (e.g. for
         "Card,APDU", see function ButtonAPDUClick below), we have
         to convert the HEX values to the real characters *)

      DataInHex:=HexStrToTxt(DataIn);
      EditDataIn.Text := TxtToHexStr(DataInHex);
      LenIn := Length(DataInHex);
      pDataIn:=@DataInHex[1];
    end else begin
      (* if RadioButtonASCII is selecte, we can use DataIn directly *)
      LenIn := Length(DataIn);
      pDataIn:=@DataIn[1];
    end;
  end;


  (* If Cmd is an invalid command, the SCardServer will create a message box
     which must be confirmed. After confirmation the program will continue
     and the component raises an ESmartCard exception.
     So, if this is the only line in the Memo field, please check for any
     message box from the SCardServer. This can happen during your development
     phase, but your final release should never use any invalid commands! *)

  try

    (* now we execute the command, Len returns the length of the data in P. *)
    Len:=SmartCard.Comand(Cmd,pDataIn,LenIn,P,BufferSize);
    (* The component throws an exception if an error occurs. Here
       we don't do any detailed error handling, but our try-finally
       block take care that at least the buffer p is freed again *)


    if Len <> 0 then begin
      (* Show DataOut in HEX *)

      (* and now show DataOut in ASCII, non printable characters become "°" *)

      DataASCII:='';
      for C:=0 to Len-1 do begin
        case P[C] of
        #0..#31: DataASCII:=DataASCII+'°';
          else DataASCII:=DataASCII+P[C];
        end;
      end;
      if DataASCII <> '' then begin
        MemoDataOut.Lines.Add(DataASCII);
      end;
    end;
  except
    on E:ESmartCard do begin (* the componen creates this exception *)
      MemoDataOut.Lines.Add(' ');
      MemoDataOut.Lines.Add('SmartcardException: '+E.Message);
    end;
    on E:Exception do begin (* we'd better catch all exceptions here *)
      MemoDataOut.Lines.Add(' ');
      MemoDataOut.Lines.Add('Exception: '+E.Message);
    end;
  end;
  FreeMem(P,BufferSize);
end;


Hoffe ihr könnt mir helfen....


Wolff68 - Fr 24.10.03 18:35

Generell könnte es an der verwendeten Schriftart liegen, da ASCII-Codes über 128 nicht "genormt" sind.
Ebenso kann es sein, daß aus Speicherplatzgründen die Zeichen auf der Karte in nur 4 Bits gespeichert werden (Also nur ASCII 0-128 zulässt)
So könnte zB aus einem ü eine { werden... (oder hab ich mich jetzt verrechnet?)

Du könntest aber mal nachsehen, welche ASCII-Codes Du von der Karte überhaupt bekommst.
Ä= 196
Ö= 214
Ü= 220
ä= 228
ö= 246
ü= 252
ß= 223

{= 123


Delete - Fr 24.10.03 19:22

Ich glaube nicht, dass die Zeichen nur mit 4 Bits codiert sind. Wie willst du sonst Müller von Mueller unterscheiden? Soll es nämlich auch geben.


Killi - Mi 29.10.03 10:06

Hi!

Die Theorie von Wolff68 könnte stimmen, da ich die Umlaute etc. schon als ~ zurückbekomme - und meine LÖSUNG für das Problem stimmt auch, ich ersetzte #225 durch ß, dann kommt die Straße richtig - allerdings werden ja äs, ös und üs auch mit einem ~ gekennzeichnet - und hie ist mein Problem, es kommen anscheinend keine Datensätze über #128 an...d.h. ich bekomme immer nur ein ~ schon im ASCII-Code.....
Kann das am Treiber liegen??? Weil das kartenlesegerät müsste es können...von der Firma gibts auch eine Krankenkassenlösung die das kann....ich versteh gar nix mehr!


Maggi - Mi 29.10.03 14:11

Hi,

kann es sein das du ineinem ganz anderen Zeichensatz unterwegs bist.

OEM oder so, dann mußt du erst konvertieren und alles wird gut. Wird auch in der Hilfe sehr gut beschrieben!

Gruß

Maggi


Killi - Mi 29.10.03 14:37

OEM Zeichensatz sagt mir leider nix, hab keine Ahnung wie die Daten codiert sind - guck dir oben mal meinen Code an, is rauskopiert - das macht den ganzen sch...! Aber da steht nur was von ASCII zu norml. Text!?
Also...!!??


Killi - Do 30.10.03 12:01

kann mir keiner mehr helfen? :(


Spieler1 - Do 30.10.03 23:57

Das geht schon, du musst nur ein unsigned char verwenden, da sind dann auch solche Sonderzeichen drin.


Killi - Fr 31.10.03 10:13

unsigned??? Wie mach ich das? Kann ja fast nix mit der Prozedur anfangen...kannst du mir helfen?


Ja-Pa - Fr 31.10.03 13:46

Maggi hat folgendes geschrieben:

OEM oder so, dann mußt du erst konvertieren und alles wird gut.


Dieses Problem habe ich auch, wenn ich ActiveX-Controls einen String übergeben will.
Der hängt sich bei Sonderzeichen dann auf.
Vielleicht muss ich das auch konvertieren?
Wie mache ich das?

Gruß, Ja-Pa


Spieler1 - Fr 31.10.03 13:49

Sorry, hab vergessen, dass das ein Delphi Forum ist und ich kein Delphi kann.
Den Typ unsigned char gibt es in C/C++, da kann man einfach schreiben:

Quelltext
1:
unsigned char meinString[100];                    

Dann hat man einen String, in dem 255 (glaub ich) verschiedene Zeichen vorkommen können, ein normaler char hat nur die Hälfte. Vielleicht hilft dir das ja auch bei Delphi irgendwie :? .
:D


Maggi - Fr 31.10.03 13:52

Hi,

Schau doch mal in der Hilfe unter "OemToAnsi" nach in der Gegend findest du einige Fkt die dir vielleicht weiter helfen!! :lol:

Gruß

Maggi


Killi - Mo 03.11.03 12:19

Das bringt mich doch alles nicht weiter, ich weiß genau dass ich die Daten in ASCII bekomme...ist etwas an der ASCII-Funktion falsch? Bekomme ja keinen Wert wie 255 oder so....weiß nicht mehr weiter!!!


Brueggendiek - Mo 03.11.03 23:47

Hallo Killi!

Nach der beliebten Winzig-Weich-Methode "Halte Dich nie an bestehende Standards, was WinzigWeich sagt, ist der neue Standard" hat der große Billy-Boy-Gates-jetzt-endlich beschlossen, daß Windows nicht mit dem ASCII-Code, sondern mit dem ANSI-Code arbeitet. Damit ist per WinzigWeicher Verfügung der bisherige Standard ASCII ungültig.

ASCII ist im Original ein 7-Bit-Code. Früher wurde bei Modem-Übertragung oft noch ein Paritätsbit verwendet, man übertrug 7 Bit + Parität, also 8 Bit zusammen.
Inzwischen gibt es einen ASCII-Standard, der mit 8 Bit arbeitet und damit auch so schöne Dinge wie Umlaute und Rahmengrafik (Blockgrafik) enthält.

Der ANSI-Code von Windows entspricht in den ersten 128 Zeichen dem ASCII-Code (7-Bit-Code). Die Zeichen ab $80 werden jedoch komplett anders belegt und sind somit nicht kompatibel zu ASCII. Insbesonders fehlen die Blockgrafikzeichen.

Bei Windows wird der ASCII-Zeichensatz als OEM-Zeichensatz bezeichnet. Damit sollte die Funktion "OEMtoANSI" einen ASCII-String - soweit die Zeichen definiert sind - in den Windows-Zeichensatz umwandeln.

Wenn Du Sicher bist, daß es ASCII ist, sollte die genannnte Funktion helfen. Wenn nicht, hilft nur das Ausprobieren, d.h. Karten mit Umlauten in den Namen organisieren und nachsehen, was da kommt. Dann mit Stringreplace oder durch zeichenweises Bearbeiten eine eigene Umwandlung realisieren.

Gruß

Dietmar Brüggendiek


Killi - Di 04.11.03 11:50

Danke für die klärende Antwort!
Strreplace hätt ich schon lange gemacht, (bin ja faul) aber das geht eben nicht, da lles als "}" angezeigt wird, ist ja die sch...! Gut, ich teste es mal mit OEMToANSI!


Killi - Di 04.11.03 12:26
Titel: hm...
...hier der neue Code, vielleicht hab ichs ja auch falsch eingebunden, OEMtoANSI steht jetzt VOR der "normalen" Textausgabe, aber es tut sich gar nix:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
procedure TFormMain.ExecSCardCmd(Cmd,DataIn: String);
const BufferSize = 32768;
var P,pDataIn: PChar;
    DataASCII, DataHex, DataInHex: String;
    C: Integer;
    Len, LenIn: LongInt;
begin
  MemoDataOut.Clear;
  if (Cmd = ''then begin
    MemoDataOut.Lines.Add('no command');
    exit;
  end;
  with EditDataIn do if ((Font.Color=clRed) and (Text='(nil)')) then DataIn:='';
  ShowCommand(Cmd,DataIn);
  P:=AllocMem(BufferSize);
  if DataIn='' then begin pDataIn:=nil; LenIn:=0end else begin
    if RadioButtonHEX.Checked then begin
      (* DataIn can either be in ASCII or in HEX, depending on the
         seleced RadioButton. If we have a HEX string (e.g. for
         "Card,APDU", see function ButtonAPDUClick below), we have
         to convert the HEX values to the real characters *)

      DataInHex:=HexStrToTxt(DataIn);
      EditDataIn.Text := TxtToHexStr(DataInHex);
      LenIn := Length(DataInHex);
      pDataIn:=@DataInHex[1];
    end else begin
      (* if RadioButtonASCII is selecte, we can use DataIn directly *)
      LenIn := Length(DataIn);
      pDataIn:=@DataIn[1];
    end;
  end;


  MemoDataOut.Lines.Add('executing command....');
  (* If Cmd is an invalid command, the SCardServer will create a message box
     which must be confirmed. After confirmation the program will continue
     and the component raises an ESmartCard exception.
     So, if this is the only line in the Memo field, please check for any
     message box from the SCardServer. This can happen during your development
     phase, but your final release should never use any invalid commands! *)

  try

    (* now we execute the command, Len returns the length of the data in P. *)
    Len:=SmartCard.Comand(Cmd,pDataIn,LenIn,P,BufferSize);
    (* The component throws an exception if an error occurs. Here
       we don't do any detailed error handling, but our try-finally
       block take care that at least the buffer p is freed again *)


    if Len = 0 then begin
      MemoDataOut.Lines.Add('command successful');
      (* in at least a message to tell the user that everything is ok *)
    end else begin
      (* Show DataOut in HEX *)
      MemoDataOut.Font.Name:='Courier';
      MemoDataOut.Font.Style:=[];
      MemoDataOut.Lines.Add('DataOut in HEX:');
      MemoDataOut.Lines.Add(' ');
      DataHEX:='';
      for C:=0 to Len-1 do begin
        DataHEX:=DataHEX+IntToHex(Ord(P[C]),2)+' ';
        if (Length(DataHex)=48then begin
          DataHEX:=DataHEX+' ['+IntToStrEx(C,3)+']';
          MemoDataOut.Lines.Add(DataHEX);
          DataHEX:='';
        end;
      end;
      if DataHEX <> '' then begin
        while Length(DataHEX)<49 do DataHEX:=DataHEX+' ';
        DataHEX:=DataHEX+'['+IntToStrEx(C,3)+']';
        MemoDataOut.Lines.Add(DataHex);
      end;
      (* and now show DataOut in ASCII, non printable characters become "°" *)
      MemoDataOut.Lines.Add(' ');
      MemoDataOut.Lines.Add('DataOut in ASCII:');
      MemoDataOut.Lines.Add(' ');
      DataASCII:='';

      OEMtoAnsi(P, P); // <-- HIER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

      for C:=0 to Len-1 do begin
        case P[C] of
          #0..#31: DataASCII:=DataASCII+'°';

      //    #132: DataASCII:=DataASCII+'ä';
      //    #142: DataASCII:=DataASCII+'Ä';
      //    #129: DataASCII:=DataASCII+'ü';
      //    #154: DataASCII:=DataASCII+'Ü';
      //    #148: DataASCII:=DataASCII+'ö';
      //    #153: DataASCII:=DataASCII+'Ö';
      //    #225: DataASCII:=DataASCII+'ß';
          else DataASCII:=DataASCII+P[C];
        end;
        if ((Length(DataASCII)>32or (P[C]=#13)) then begin
          if (P[C]=#13then begin (* after a <CR>, we start a new line *)
            while Length(DataASCII)<37 do DataASCII:=DataASCII+' ';
            DataASCII:=DataASCII+'(#13 found) ';
          end else while Length(DataASCII)<49 do DataASCII:=DataASCII+' ';
          MemoDataOut.Lines.Add(DataASCII+'['+IntToStrEx(C,3)+']');
          DataASCII:='';
        end;
      end;
      if DataASCII <> '' then begin
        while Length(DataASCII)<49 do DataASCII:=DataASCII+' ';
        MemoDataOut.Lines.Add(DataASCII+'['+IntToStrEx(C,3)+']');
      end;
    end;
  except
    on E:ESmartCard do begin (* the componen creates this exception *)
      MemoDataOut.Lines.Add(' ');
      MemoDataOut.Lines.Add('SmartcardException: '+E.Message);
    end;
    on E:Exception do begin (* we'd better catch all exceptions here *)
      MemoDataOut.Lines.Add(' ');
      MemoDataOut.Lines.Add('Exception: '+E.Message);
    end;
  end;
  FreeMem(P,BufferSize);
end;



Moderiert von user profile icontommie-lie: Code- durch Delphi-Tags ersetzt


elysm - Mi 05.11.03 10:58

Zitat:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
      for C:=0 to Len-1 do begin 
        case P[C] of 
          #0..#31: DataASCII:=DataASCII+'°'; 

      //    #132: DataASCII:=DataASCII+'ä'; 
      //    #142: DataASCII:=DataASCII+'Ä'; 
      //    #129: DataASCII:=DataASCII+'ü'; 
      //    #154: DataASCII:=DataASCII+'Ü'; 
      //    #148: DataASCII:=DataASCII+'ö'; 
      //    #153: DataASCII:=DataASCII+'Ö'; 
      //    #225: DataASCII:=DataASCII+'ß'; 
          else DataASCII:=DataASCII+P[C];

nimm doch einfach mal die slash´s vor den angaben weg!! das wäre das erste gewesen was ich gemacht hätte!
es sei den du hast die dahin gemacht.. denn hab ich nix gesagt! ;)


Killi - Mi 05.11.03 11:37

die hab ich dahin gemacht weils nix bringt......das is ja die scheibenwischanlage