2

This is driving me crazy. I have been two days converting my string from one type to another with no success.

I'm using Delphi Rio and I need to convert a string to HEX or DEC, but the string contains special characters, like á é í ó ú ñ or €.

For example, the 'á' character is 160 (dec) or A0 (hex). However, I'm getting 225, 145, 241 depending on the string type (ansichar, utf8, widechar...) but I don't know how can I get the real 160 value.

I need this because I want to send special characters to a bluetooth printer. If I send this:

edit1.text := 'áéíóú€$';
FSocket.SendData(TEncoding.ASCII.GetBytes(edit1.Text));

Printer receives this (HEX):

3F 3F 3F 3F 3F 3F 24

However, it should receive this (HEX):

A0 82 A1 A2 A3 D5 24

That's because I'm getting the wrong ASCII value for each character (63 is the ascii code for '?' character).

So... how can I send the real ASCII text to the printer? How can I get the real ascii code for 'á' (160)?

Please help!

santycg
  • 119
  • 1
  • 8
  • 4
    None of these characters exist in the [ASCII table](http://www.asciitable.com/). That's easy to check. It has a mere 128 values in it. In order to help you I think you need to tell us more about what encoding the printer really wants. It's also time for you to do a websearch with the search term **Unicode**, which I suspect will be something of an eye opener. We can only hope that the printer accepts one of the common Unicode encodings. I'd be surprised if it didn't, given that Bluetooth was invented long after Unicode! – David Heffernan Mar 04 '20 at 15:04
  • ASCII only has 0-127 – MrTux Mar 04 '20 at 15:05
  • David is right. The `á` character doesn't exist in the [ASCII character set](https://en.wikipedia.org/wiki/ASCII). Thus, it has no ASCII code. – Andreas Rejbrand Mar 04 '20 at 15:06
  • @J... Do you know that there are many different Windows ANSI encodings? It's not all 1252! – David Heffernan Mar 04 '20 at 15:07
  • @DavidHeffernan Yes, I do know that. I hope OP does too. – J... Mar 04 '20 at 15:07
  • @J... I think it's pretty clear that OP does not know this yet. Suggesting that ANSI is the solution without knowing anything about the printer seems very speculative. We don't have enough information yet to suggest solutions. – David Heffernan Mar 04 '20 at 15:08
  • @DavidHeffernan We know the byte values OP expects and we know that it isn't 1252, but it is some type of ANSI encoding as OP has told us the expected result. – J... Mar 04 '20 at 15:14
  • 2
    Nobody invents a Bluetooth printer that doesn't support Unicode – David Heffernan Mar 04 '20 at 15:16
  • I also love the fact that these characters can be termed "special characters". They are no more special than other letters like A B C! – David Heffernan Mar 04 '20 at 15:16
  • 3
    Actually, `A0` is a non-breaking space in all ANSI codepages. This is most likely the old DOS OEM Charset. (á -> 0xA0/160) – J... Mar 04 '20 at 15:19
  • In other words, [codepage 850](https://en.wikipedia.org/wiki/Code_page_850)? Anyway, it's hard to answer this question, because there are different problems, at least 1: how to convert from 'normal' unicode strings to other formats and 2: what format to you actually need for your printer? – GolezTrol Mar 04 '20 at 15:23
  • Hooray, `TEncoding.GetEncoding(850)` to the rescue, and we can continue pretending that Unicode doesn't exist!! ;-) – David Heffernan Mar 04 '20 at 15:25
  • Does this answer your question? [Connect via Bluetooth with Delphi XE7 using portable printer](https://stackoverflow.com/questions/29946885/connect-via-bluetooth-with-delphi-xe7-using-portable-printer). Bumped into this when searching for `FSocket.SendData`. :p – GolezTrol Mar 04 '20 at 15:27
  • @DavidHeffernan Actually, it's not 850 - the Euro symbol tells us its something else. Probably [codepage 858](https://en.wikipedia.org/wiki/Code_page_858). Would be great if OP just read their printer manual... – J... Mar 04 '20 at 15:29
  • @DavidHeffernan `Nobody invents a Bluetooth printer that doesn't support Unicode` - oh, they most certainly do. I think you would be surprised. – J... Mar 04 '20 at 16:15
  • @J... From China? – David Heffernan Mar 04 '20 at 16:35
  • @DavidHeffernan From anywhere. EPOS devices move slowly towards the future... – J... Mar 04 '20 at 17:07
  • 2
    @DavidHeffernan Just picked one at random [Epson TM-T20II](https://epson.com/For-Work/Printers/POS/TM-T20II-POS-Receipt-Printer/p/C31CD52062). Specs -> character sets. Note the conspicuous [absence of unicode](https://reference.epson-biz.com/modules/ref_charcode_en/index.php?content_id=1). From the tree on the left, the only multi-byte character sets that are supported are old non-unicode JIS japanese sets. And this is a contemporary Epson - cheaper units definitely don't commonly support unicode. – J... Mar 04 '20 at 17:14

1 Answers1

11

First, there is no such thing as a real ASCII code for characters beyond 0x7F. ASCII defines 7-bit characters only. When considering text encoding using characters in the upper half (0x80->0xFF) of the 8-bit character range the encodings are no longer ASCII, but ANSI, and there are hundreds of different encoding schemes, all of which support different varieties of special characters. The complete mutual incompatibility of ANSI encoding schemes is one of the main drivers for the development and migration to Unicode.

We can deduce from your expected outputs that the ANSI codepage you are trying to map to is Code Page 858. Your printer manual probably tells you this somewhere, but for now we will assume that this is the only input the printer accepts. It's always a good idea to read your manuals - they will save you endless headaches in the future. As David noted, if you can use Unicode, this should always be your first, best option.

You can extract the desired bytes using the TEncoding class like :

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var      
  LEncoding : TEncoding;
  tb : TBytes;
  b : Byte;
begin
  LEncoding := TEncoding.GetEncoding(858);
  try
    tb := LEncoding.GetBytes('áéíóú€$');
  finally
    LEncoding.Free;
  end;
  for b in tb do Write(IntToHex(b,2) + ' ');    
  ReadLn;    
end.

This produces output :

 A0 82 A1 A2 A3 D5 24
J...
  • 30,968
  • 6
  • 66
  • 143
  • That's the problem. I have no user manual at all. It is a POS wireless printer from China. I have read a lot of chinese pages indeed :( I will try your code and let you know what I get. Thanks btw. – santycg Mar 04 '20 at 15:51
  • @user1461672 Surely a manual exists. What is the make and model number? – J... Mar 05 '20 at 13:02
  • GOOJPRT PT-210. I have found some user manuals online for other similar models and brands. All of them seems to use the same ESC/POS commands. The problem was the Encoding itself, not the communication with the printer or the commands to use. – santycg Mar 05 '20 at 16:42
  • BTW, I can finally print thanks to your answer. That's why I marked your answer as a solution. This is the code I use: FSocket.SendData(TEncoding.ascii.GetEncoding(858).GetBytes(edit1.Text)); – santycg Mar 05 '20 at 16:44
  • @user1461672 Wow. What a piece of junk. I don't even think that's a real company - they don't even have a website. Hazards of buying bootleg hardware from an alibaba shipping container... The listings I've seen at least claim that there's a manual in the box. – J... Mar 05 '20 at 17:48
  • 2
    Your code, in the latest comment, leaks. The code in the answer you accepted does not leak. Why do you make such choices? Your broken code suggests that you still think that this is ASCII. It's not. Use the code in the answer please. – David Heffernan Mar 06 '20 at 07:25
  • @user1461672 Please take note of David's comment. The code you've decided to use indeed leaks the TEncoding instance generated by the call to `.GetEncoding(858)`. You *must* free that instance or your program will leak memory every time it is called. This will eventually cause your program to crash. – J... Mar 06 '20 at 11:42
  • Ok, I have now converted your code in a function that returns the bytes and I send them directly with FSocket.SendData(). Thanks. – santycg Mar 06 '20 at 12:01