Prüfen ob Char Grad-Zeichen

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Prüfen ob Char Grad-Zeichen

Beitrag von mschnell »

theo hat geschrieben:In vielen Bereichen hat das Set of Char bei Unicode sowieso ausgedient.
Ein Set of WideChar hat ein bisschen viele Bits :) .

-Michael

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Prüfen ob Char Grad-Zeichen

Beitrag von theo »

Schon und WideChar reicht ja nicht wirklich aus. 4 Bytes müssten es sein.

Übrigens (passt grad ins Thema):
In diesem Thread http://www.lazarusforum.de/viewtopic.php?p=26655#p26655" onclick="window.open(this.href);return false; war die allg. Meinung, dass man den TCharacter Typen mit Hilfe des OS erstellen will, statt einkompilierte Tabellen (wie bei utf8proc_pas) zu verwenden.

Wie ich heute gelesen habe, hat sich aus irgendwelchen Gründen sogar CodeGear D2009 (Windows Only) nicht dazu entschieden, das via WinAPI zu machen, sondern die Tabellen in die Anwendung zu bauen:

https://forums.codegear.com/message.jsp ... 3756#53756" onclick="window.open(this.href);return false;

Nils
Beiträge: 130
Registriert: Mo 28. Mai 2007, 12:36
Kontaktdaten:

Re: Prüfen ob Char Grad-Zeichen

Beitrag von Nils »

theo: Ich verstehe nicht, was das werden soll. Du knallst alle falschen Zeichen in einen String, der von deiner Klasse korrigiert wird ? Wie soll ich das in einen Algo einbauen ? Beispiel:

Code: Alles auswählen

if (s[i] in ['0'..'9']) or
    (
      ((Length(Result) > 0) and (s[i] in ['-', '+']))
      and
        (
          (Result[High(Result)].Wertigkeit in [6, 9, 8])
          or
          (Result[High(Result)].Wertigkeit = -1)
        )
    )
    then
    begin
      // Hier kann man leicht nicht erlaubte mathematische Operatorenfolgen auszuschließen: ++ und -+ und ^+
      if s[i] = '+' then
        raise Exception.Create('[TOKENIZER] -+ oder ++ oder ^+ gefunden. Abbruch.');
      // Damit auch Zahlen >9 als EIN Token vorhanden sind, muss der String bei dem ersten Kontakt mit einer Zahl näher untersucht werden
      Tmp := ScanNumber(s, i);
      AddArray(Tmp, 0);
      inc(i, Length(Tmp));
    end else
    if s[i] in ['a'..'z', 'A'..'Z'] then
    begin
      // Buchstaben weisen eindeutig auf Funktionen hin.
      ka := -1;
      ke := -1;
      j  := i;
      // Da eine Funktion einen Parameter besitzt, welcher in Klammern steht, müssen die Positionen der Klammern im String bestimmt werden.
      while (j < Length(s)) do
      begin
        if s[Succ(j)] = '(' then
          ka := Succ(j)
        else
        if s[Succ(j)] = ')' then
        begin
          ke := Succ(j);
          Break;
        end;
        inc(j);
      end;
      if (ka <> -1) and (ke <> -1) then
      begin
        // Sind beide Klammern gefunden worden, muss man...
        // ...die öffnende Klammer als Token hinzufügen
        AddArray('(', -1);
        // ...den Funktionsterm als Tokens hinzufügen
        Result := TokenizeInfix(Copy(s, Succ(ka), Pred(ke-ka)));
        // ...die schließende Klammer als Token hinzufügen
        AddArray(')', -2);
        AddArray(Copy(s, i, ka-i), 10);
      end else
        // Ist kein Parameter vorhanden, handelt es sich um keine Funktion. Abbruch.
        raise Exception.Create('[TOKENIZER] Funktion enthält keinen Parameter. Abbruch.');
      i := Succ(ke);
    end else
    // Operatoren
    // Fakultäten und DegToRad ähneln von der endgültigen Abarbeitung her der Potenz
    if s[i] in ['^', '!', '°'] then
    begin
      AddArray(s[i], 9); // Potenz vor...
      inc(i, Length(s[i]));
    end else
    if s[i] in ['*', '/', '%'] then
    begin
      AddArray(s[i], 8); // Punkt vor...
      inc(i, Length(s[i]));
    end else
    if s[i] in ['+', '-'] then
    begin
      AddArray(s[i], 6); // Strich vor...
      inc(i, Length(s[i]));
    end else
    if s[i] = '(' then
    begin
      AddArray(s[i], -1); // Klammer auf.
      inc(i, Length(s[i]));
    end else
    if s[i] = ')' then
    begin
      AddArray(s[i], -2); // Die Wertigkeit ist nur -2, da die Wertigkeit an sich unbedeutend und somit regelrecht am niedrigsten ist
      inc(i, Length(s[i]));
    end else
    // Leerzeichen werden ignoriert
    if s[i] = ' ' then
      inc(i)
    else
      // Im Falle eines unbekannten Zeichens, ist die Weiterzerlegung unmöglich.
      raise Exception.Create('[TOKENIZER] Token "'+s[i]+'" unbekannt. Abbruch.');
Meine Musik: spiker-music.net

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Prüfen ob Char Grad-Zeichen

Beitrag von mschnell »

Das mit UTF-8 umzusetzen macht wirklich keinen Spaß... Vielleicht doch besser Widestring ????? Damit geht zwar "set" auch nicht, aber immerhin funzt s und case.

-Michael

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Prüfen ob Char Grad-Zeichen

Beitrag von theo »

@nils: Das mit dem Set-Ersatz ist eigentlich eine Dreingabe.
Die Grundfunktion ist, dass US.Next immer den nächsten Buchstaben in UCS-4 zurückliefert (Cardinal), unabhängig davon, wie viele Bytes der in UTF-8 belegt.
Code der sich darauf verlässt, dass AnsiString ein ganzes Zeichen ist kann man nicht mehr direkt weiterverwenden mit UTF-8. Das könnte man nur im Compiler selber ändern.

Vielleicht kommst du in deinem Fall über die Konvertierung nach WideString tatsächlich schneller zum Ziel
Deine if s in ['^', '!', '°'] kannst du schon gebrauchen im unteren Bereich, nur musst du dir bewusst sein, dass dein Editor mit UTF-8 arbeitet.
Schaue das Zeichen in der Lazarus Zeichentabelle nach und ersetze es durch den Hexwert z.B. if s in ['^', '!', #$B0]. Das funzt dann aber nur mit WideString.

Der Haken an deinem Code ist wirklich nur das Grad-Zeichen, sonst würde es wahrscheinlich auch mit UTF-8 funzen. Aber das Ding ist nun mal im Latin1 Supplement Bereich und nicht in ASCII.

Nils
Beiträge: 130
Registriert: Mo 28. Mai 2007, 12:36
Kontaktdaten:

Re: Prüfen ob Char Grad-Zeichen

Beitrag von Nils »

Ich habe nun den Funktionsparameter zu WideString geändert und prüfe in der Funktion nun auf #$B0, allerdings trifft diese If-Abfrage nie zu. Muss ich noch irgendetwas mit dem String aus dem Edit vorher anstellen ?
Meine Musik: spiker-music.net

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Prüfen ob Char Grad-Zeichen

Beitrag von theo »

WS:=UTF8Decode(Memo1.Text) und UTF8Encode, wenn du's wieder ins Memo lädst.

Nils
Beiträge: 130
Registriert: Mo 28. Mai 2007, 12:36
Kontaktdaten:

Re: Prüfen ob Char Grad-Zeichen

Beitrag von Nils »

Hm, der Fehler besteht trotz UTF8Decode weiterhin. Hier mal alles stark gekürzt (damit es schöner aussieht, lasse ich die [...] mal weg, wären nämlich ziemlich viele).

Code: Alles auswählen

var Tokens: TDynTokenArray;
begin
  Tokens := TokenizeInfix(UTF8Decode(e.Text));
end;
 
function TfrmMain.TokenizeInfix(s : WideString) : TDynTokenArray;
  procedure AddArray(aInhalt : WideString; aWertigkeit : Integer);
  begin
    SetLength(Result, Succ(Length(Result)));
    with Result[High(Result)] do
    begin
      Inhalt     := aInhalt;
      Wertigkeit := aWertigkeit;
    end;
  end;
var i : Integer;
begin
  i := 1;
  while i <= Length(s) do
  begin
    if s[i] in ['^', '!', #$B0] then
    begin
      AddArray(s[i], 9);
      inc(i, Length(s[i]));
    end else
      raise Exception.Create('[TOKENIZER] Token "'+s[i]+'" unbekannt. Abbruch.');
  end;
end;
Wichtig: Zur Zeit basiert der Typ TToken (TDynTokenArray = Array of TToken) noch auf Strings, da ich erstmal schauen muss, wie ich meinem Stack WideString beibringe. Aber es dürfte trotzdem keine Begründung für die Exception sein: "[TOKENIZER] Token '°' unbekannt. Abbruch."

Falls nichts hilft, kann ich das Projekt hochladen, es ist schließlich komplett kommentiert und ich habe mir Mühe gegeben, es auch allgemein übersichtlich zu gestalten. Aber das nur am Rande, denn ich hoffe mal, dass der gekürzte Code schon den Fehler sichtbar macht.
Meine Musik: spiker-music.net

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Prüfen ob Char Grad-Zeichen

Beitrag von theo »

K.A. Was gibt er denn zurück, wenn du dir Ord(S) ausgeben lässt bei der Exception? Entspricht das $B0?

Nils
Beiträge: 130
Registriert: Mo 28. Mai 2007, 12:36
Kontaktdaten:

Re: Prüfen ob Char Grad-Zeichen

Beitrag von Nils »

IntToStr(Ord(s)) liefert mir 176. 176 ist der ASCII-Code vom Grad-Zeichen. Erscheint mir also falsch.
Meine Musik: spiker-music.net

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Prüfen ob Char Grad-Zeichen

Beitrag von theo »

Vielleicht fummelt da der WideString Manager rein.

Probier mal das

Code: Alles auswählen

initialization
 widestringmanager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove;
 widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2WideMove; 
...

Nils
Beiträge: 130
Registriert: Mo 28. Mai 2007, 12:36
Kontaktdaten:

Re: Prüfen ob Char Grad-Zeichen

Beitrag von Nils »

Das war der Grund dafür. Nun muss ich den Stack noch anpassen, denn die Zugriffsverletzung welche ich jetzt kriege, scheint mit dem Stack zusammenzuhängen. In dem Sinne mach ich lieber ein neues Thema auf (zur Übersichtlichkeit) und bedanke mich für eure tolle Hilfe!
Meine Musik: spiker-music.net

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Prüfen ob Char Grad-Zeichen

Beitrag von mschnell »

Nils hat geschrieben:Ich habe nun den Funktionsparameter zu WideString geändert und prüfe in der Funktion nun auf #$B0, allerdings trifft diese If-Abfrage nie zu. Muss ich noch irgendetwas mit dem String aus dem Edit vorher anstellen ?
Du kannst in Lazarus nicht einfach eine String-Konstante auf einen Widetring zuordnen oder mit einem Widestring vergleichen. In lazarus kommen String-Konstanten als UTF-8 heraus, der FPC-Compiler hält sie aber für ANSI (er hat keinen funktionalen UTF8-Typ) und konvertiert sie dann so (also völlig falsch) in Widestrings. Du musst bei allen Konstanten (und immer wenn Du einen WideString an LCL übergeben oder von der LCL empfangen willst)eine explizite Umwandlungs-Routine Widestring <-> UTF8 aufrufen.

-Michael

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Prüfen ob Char Grad-Zeichen

Beitrag von mse »

mschnell hat geschrieben:In lazarus kommen String-Konstanten als UTF-8 heraus, der FPC-Compiler hält sie aber für ANSI (er hat keinen funktionalen UTF8-Typ) und konvertiert sie dann so (also völlig falsch) in Widestrings.
Bleibt noch anzumerken, dass der Compiler das schon richtig machen würde, falls er wüsste, dass der Quelltext in utf-8 gespeichert ist, also beispielsweise durch Angabe von -Fcutf8 beim kompilieren. Da Lazarus auf allen Platformen utf-8 codierte ansistrings verwendet, wird diese Vorgehensweise leider verunmöglicht.

Antworten