Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2010-02

UTF-8 string recognition

15 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

JoshyFun
to Antônio

Hello Lazarus-List,

Saturday, February 27, 2010, 5:43:24 PM, you wrote:

A> Mainly from ANSI, but whatever.

You can not determine if a string is an UTF8 one, only if it is an UTF8 well formed sequence. In other words, you can not detect if a string IS an UTF8, only if it does not have UTF8 errors.

You can use the LCLProc FindInvalidUFT8Character function.

Best regards, JoshyFun

Reply by email

Antônio
to JoshyFun

There is no way to determine whether a string is in ANSI format or not?

Ant?nio

2010/2/27 JoshyFun :

Show quoted text 23 lines
Hello Lazarus-List, Saturday, February 27, 2010, 5:43:24 PM, you wrote: A> Mainly from ANSI, but whatever. You can not determine if a string is an UTF8 one, only if it is an UTF8 well formed sequence. In other words, you can not detect if a string IS an UTF8, only if it does not have UTF8 errors. You can use the LCLProc FindInvalidUFT8Character function. -- Best regards, ?JoshyFun -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Mattias Gaertner
to Antônio
There is no way to determine whether a string is in ANSI format or not?

In general: No, because every 8bit combination is valid. In specific case: Not every combination makes sense. So you can write heuristics.

You should save/define the encoding of a string. For example all strings in the LCL are UTF-8.

Mattias

Reply by email

Antônio
to Mattias Gaertner

I refer to a text loaded in a SynEdit by the user in which I need to make some string manipulations.

Ant?nio

2010/2/28 Mattias Gaertner :

Show quoted text 20 lines
On Sun, 28 Feb 2010 00:46:12 -0300 Ant?nio wrote: > There is no way to determine whether a string is in ANSI format or not? In general: No, because every 8bit combination is valid. In specific case: Not every combination makes sense. So you can write heuristics. You should save/define the encoding of a string. For example all strings in the LCL are UTF-8. Mattias -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Santiago A.
to Antônio: How to determine whether a string is UTF-8 or not?

Not every ansi string is a valid UTF8 string, but every UTF8 string is a valid ansi string. So you can be sure that a string is not a valid UTF8 string, if it's a valid, it could be a UTF8 or an ansi string.

You can make some guess, for latin alphabet (western or eastern), if it is a valid UTF8 and it has several char(195) then probably you have an UTF8 string with several above char(128) characters. But you are just guessing, it could be an UTF8 with no acute or tilde letters, or it could be an ansi string with several char(195).

El 27/02/2010 2:17, Ant?nio escribi?:

Show quoted text 8 lines
How to determine whether a string is UTF-8 or not? -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Robin Hoo
to Antônio: How to determine whether a string is UTF-8 or not?

Hi, Antonio

Pls check the function I used for check UTF8 string. Hope it helpful

function IsUTF8(UnknownStr:string):boolean;
var
    i    :Integer;
begin
    if length(UnknownStr)=0 then exit(true);
    i:=1;
    while i<length(UnknownStr) do
    begin
        // ASCII
        if  (UnknownStr[i] = #$09) or
            (UnknownStr[i] = #$0A) or
            (UnknownStr[i] = #$0D) or
            (UnknownStr[i] in [#$20..#$7E]) then
        begin
            inc(i);
            continue;
        end;
        // non-overlong 2-byte
        if  (UnknownStr[i] in [#$C2..#$DF]) and
            (UnknownStr[i+1] in [#$80..#$BF]) then
        begin
            inc(i,2);
            continue;
        end;
        // excluding overlongs
        if ((UnknownStr[i]=#$E0) and
              (UnknownStr[i+1] in [#$A0..#$BF]) and
            (UnknownStr[i+2] in [#$80..#$BF]))
        or
            // straight 3-byte
            (((UnknownStr[i] in [#$E1..#$EC]) or
            (UnknownStr[i] = #$EE) or
            (UnknownStr[i] = #$EF))
            and
            (UnknownStr[i+1] in [#$80..#$BF]) and
            (UnknownStr[i+2] in [#$80..#$BF]))
        or
             // excluding surrogates
             ((UnknownStr[i]=#$ED) and
              (UnknownStr[i+1] in [#$80..#$9F]) and
              (UnknownStr[i+2] in [#$80..#$BF])) then
        begin
                inc(i,3);
                continue;
        end;
        // planes 1-3
        if ((UnknownStr[i]=#$F0) and
            (UnknownStr[i+1] in [#$90..#$BF]) and
            (UnknownStr[i+2] in [#$80..#$BF]) and
            (UnknownStr[i+3] in [#$80..#$BF]))
        or
        // planes 4-15
           ((UnknownStr[i] in [#$F1..#$F3]) and
            (UnknownStr[i+1] in [#$80..#$BF]) and
            (UnknownStr[i+2] in [#$80..#$BF]) and
            (UnknownStr[i+3] in [#$80..#$BF]))
        or
        // plane 16
           ((UnknownStr[i]=#$F4) and
            (UnknownStr[i+1] in [#$80..#$8F]) and
            (UnknownStr[i+2] in [#$80..#$BF]) and
            (UnknownStr[i+3] in [#$80..#$BF])) then
        begin
            inc(i,4);
            continue;
        end;
        exit(false);
    end;
    exit(true);
end;

2010/2/27 Ant?nio

Show quoted text 8 lines
How to determine whether a string is UTF-8 or not? -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20100303/2baa419a/attachment.html>

Reply by email

Mattias Gaertner
to Robin Hoo
Hi, Antonio Pls check the function I used for check UTF8 string. Hope it helpful

You combine a IsText (no special characters in #0-#31) and IsUTF8 - good idea.

function IsUTF8(UnknownStr:string):boolean;

Maybe better name it IsUTF8Text ?

Show quoted text 12 lines
var i :Integer; begin if length(UnknownStr)=0 then exit(true); i:=1; while i<length(UnknownStr) do begin // ASCII if (UnknownStr[i] = #$09) or (UnknownStr[i] = #$0A) or (UnknownStr[i] = #$0D) or (UnknownStr[i] in [#$20..#$7E]) then

#12 is a valid character too in texts (form feed).

Show quoted text 57 lines
begin inc(i); continue; end; // non-overlong 2-byte if (UnknownStr[i] in [#$C2..#$DF]) and (UnknownStr[i+1] in [#$80..#$BF]) then begin inc(i,2); continue; end; // excluding overlongs if ((UnknownStr[i]=#$E0) and (UnknownStr[i+1] in [#$A0..#$BF]) and (UnknownStr[i+2] in [#$80..#$BF])) or // straight 3-byte (((UnknownStr[i] in [#$E1..#$EC]) or (UnknownStr[i] = #$EE) or (UnknownStr[i] = #$EF)) and (UnknownStr[i+1] in [#$80..#$BF]) and (UnknownStr[i+2] in [#$80..#$BF])) or // excluding surrogates ((UnknownStr[i]=#$ED) and (UnknownStr[i+1] in [#$80..#$9F]) and (UnknownStr[i+2] in [#$80..#$BF])) then begin inc(i,3); continue; end; // planes 1-3 if ((UnknownStr[i]=#$F0) and (UnknownStr[i+1] in [#$90..#$BF]) and (UnknownStr[i+2] in [#$80..#$BF]) and (UnknownStr[i+3] in [#$80..#$BF])) or // planes 4-15 ((UnknownStr[i] in [#$F1..#$F3]) and (UnknownStr[i+1] in [#$80..#$BF]) and (UnknownStr[i+2] in [#$80..#$BF]) and (UnknownStr[i+3] in [#$80..#$BF])) or // plane 16 ((UnknownStr[i]=#$F4) and (UnknownStr[i+1] in [#$80..#$8F]) and (UnknownStr[i+2] in [#$80..#$BF]) and (UnknownStr[i+3] in [#$80..#$BF])) then begin inc(i,4); continue; end; exit(false); end; exit(true); end;

Mattias

Reply by email

JoshyFun
to Robin Hoo: Hi, Antonio Pls check the function I used for check UTF8 string. Hope it helpful function…

Hello Lazarus-List,

Wednesday, March 3, 2010, 12:24:35 AM, you wrote:

RH> Pls check the function I used for check UTF8 string. Hope it helpful
RH> function IsUTF8(UnknownStr:string):boolean;

Well, there is a lot of UTF8 strings that do not pass your checks ;) If you remove low ascii control chars what happend with UTF8 control chars ?

RH> var
RH> i :Integer;
RH> begin
RH> if length(UnknownStr)=0 then exit(true);
RH> i:=1;
RH> while i<length(UnknownStr) do
RH> begin
RH> // ASCII
RH> if (UnknownStr[i] = #$09) or
RH> (UnknownStr[i] = #$0A) or
RH> (UnknownStr[i] = #$0D) or
RH> (UnknownStr[i] in [#$20..#$7E]) then RH> begin
RH> inc(i);
RH> continue;
RH> end;
RH> // non-overlong 2-byte
RH> if (UnknownStr[i] in [#$C2..#$DF]) and RH> (UnknownStr[i+1] in [#$80..#$BF]) then RH> begin

It should crashes here with strings like:

var
 s: string;
begin
 s:=$C2;
 IsUTF8(s);
end;

which is not valid UTF8.

RH> // excluding surrogates
RH> ((UnknownStr[i]=#$ED) and
RH> (UnknownStr[i+1] in [#$80..#$9F]) and RH> (UnknownStr[i+2] in [#$80..#$BF])) then

Surrogates are not UTF8 valid codepoints.

Best regards, JoshyFun

Reply by email

Robin Hoo
to JoshyFun

Hi, JoshyFun

Thanks for pointing out the bug in my coding, yes you are right. I forgot to put some checking before every inc(i,k) and continue; there should a judgement statement
*if i>length(UnknownStr) then exit(false);*

2010/3/3 JoshyFun

Show quoted text 61 lines
Hello Lazarus-List, Wednesday, March 3, 2010, 12:24:35 AM, you wrote: RH> Pls check the function I used for check UTF8 string. Hope it helpful RH> function IsUTF8(UnknownStr:string):boolean; Well, there is a lot of UTF8 strings that do not pass your checks ;) If you remove low ascii control chars what happend with UTF8 control chars ? RH> var RH> i :Integer; RH> begin RH> if length(UnknownStr)=0 then exit(true); RH> i:=1; RH> while i<length(UnknownStr) do RH> begin RH> // ASCII RH> if (UnknownStr[i] = #$09) or RH> (UnknownStr[i] = #$0A) or RH> (UnknownStr[i] = #$0D) or RH> (UnknownStr[i] in [#$20..#$7E]) then RH> begin RH> inc(i); RH> continue; RH> end; RH> // non-overlong 2-byte RH> if (UnknownStr[i] in [#$C2..#$DF]) and RH> (UnknownStr[i+1] in [#$80..#$BF]) then RH> begin It should crashes here with strings like: var s: string; begin s:=$C2; IsUTF8(s); end; which is not valid UTF8. RH> // excluding surrogates RH> ((UnknownStr[i]=#$ED) and RH> (UnknownStr[i+1] in [#$80..#$9F]) and RH> (UnknownStr[i+2] in [#$80..#$BF])) then Surrogates are not UTF8 valid codepoints. -- Best regards, JoshyFun -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20100303/5bcd2fe8/attachment.html>

Reply by email

Hans-Peter Diettrich
to JoshyFun: RH> Pls check the function I used for check UTF8 string. Hope it helpful RH> function…
Show quoted text 38 lines
RH> Pls check the function I used for check UTF8 string. Hope it helpful RH> function IsUTF8(UnknownStr:string):boolean; Well, there is a lot of UTF8 strings that do not pass your checks ;) If you remove low ascii control chars what happend with UTF8 control chars ? RH> var RH> i :Integer; RH> begin RH> if length(UnknownStr)=0 then exit(true); RH> i:=1; RH> while i<length(UnknownStr) do RH> begin RH> // ASCII RH> if (UnknownStr[i] = #$09) or RH> (UnknownStr[i] = #$0A) or RH> (UnknownStr[i] = #$0D) or RH> (UnknownStr[i] in [#$20..#$7E]) then RH> begin RH> inc(i); RH> continue; RH> end; RH> // non-overlong 2-byte RH> if (UnknownStr[i] in [#$C2..#$DF]) and RH> (UnknownStr[i+1] in [#$80..#$BF]) then RH> begin It should crashes here with strings like: var s: string; begin s:=$C2; IsUTF8(s); end; which is not valid UTF8.

That's correct, a possible workaround were the use of PChars, which can safely access the appended #0.

I'd suggest a state machine or the like for the implementation:
   while True do
     case p^ of
     #0: break; //done, okay if past the end of the string
     #8, #10, #12, #13, ' '..#$7E: inc(p); //okay
     #$C0..#$DF: ... //2 bytes
     #$E0..#$EF: ... //3 bytes
     #$F0..#$F4: ... //4 bytes
     else exit(False); //not valid text
     end;

DoDi

Reply by email

JoshyFun
to Robin Hoo: Hi, JoshyFun Thanks for pointing out the bug in my coding, yes you are right. I forgot to…

Hello Lazarus-List,

Wednesday, March 3, 2010, 2:05:48 PM, you wrote:

RH> Hi, JoshyFun

RH> Thanks for pointing out the bug in my coding, yes you are right. I forgot to RH> put some checking before every inc(i,k) and continue; there should a RH> judgement statement
*if i>>length(UnknownStr) then exit(false);*

You can check the UTF8ToUnicode function in FPC sources located at:

rtl\inc\wstrings.inc

Best regards, JoshyFun

Reply by email