Sprawdzenie istnienia znaku "ą" w zadanym ciągu znaków

0

Cześć,
mam na formie komponent np Memo. Lece teraz w pętli po znakach i chce zamienić je na kody ASCII. Problem w tym kiedy trafiam na polski znak. Pomyślałem, że zrobię tak:

for i:=1 to Length(Memo.Text) do
begin
  if Memo.Text[i]='ą' then
  //cos tam robimy
  else
  Ord(Memo.Text[i]); //oczywiscie wielkie uproszczenie bo gdzies sobie to wrzucam
end;

Niestety taka konstrukcja ifa nie działa bo nie wykrywa mi w ten sposób 'ą'. Czy mogę to jakoś inaczej sprawdzić? tzn zamieniac sobie znaki na ascii a kiedy trafie na 'polski' znak to wykonac jakas inna czynnosc?

2

Lazarus od wesji 1.6 (fpc 3.0.0) domyślnie wszystkie stringi przetrzymuje jako utf8. Ą w utf8 to 2 bajty, więc memo.text[i], wskaże tylko pierwszy bajt. W tym celu można wykorzystać UTF8Length i UTF8Copy (unit LazUTF8), np.

 for i:=1 to UTF8Length(memo.text) do
if Length(UTF8Copy(memo.text, i, 1))=1 then // jeżeli znak jednobajtowy 
//zrób cośtam, np. Ord()
else
//jeżeli to ą ę i inne kilkubajtowe znaki to zrób coś innego

Tutaj do poczytania: http://wiki.freepascal.org/Better_Unicode_Support_in_Lazarus

1

W sumie to Lazarus już od dawien dawna używa UTF-8 dla łańcuchów znaków :]

karpov napisał(a)

Niestety taka konstrukcja ifa nie działa bo nie wykrywa mi w ten sposób 'ą'.

Dlatego że literał ą jest dwubajtowy, czyli jest literałem łańcuchowym, a nie znakowym; Zresztą to nie jest dziwne, bo teoretycznie próbujesz porównać jeden bajt do dwóch bajtów;

W swoim projekcie wykorzystuję funkcję do translacji kodów znaków na kody wewnętrzne, w celu przyporządkowania ich do konkretnych wycinków obrazu PNG; Mechanizm tłumaczący kody znaków otrzymuje na wejściu ciąg typu String, czyli natywnie kodowany w UTF-8, a na wyjściu wypluwa jednobajtowe kody wewnętrzne wszystkich znaków z łańcucha; To tak ogólnie pisząc, niezbyt precyzyjnie;

Do czego zmierzam - mechanizm ten bazuje na wskaźnikach na znaki (typ PChar), z których korzysta funkcja UTF8CharacterToUnicode z modułu LazUTF8 - funkcja ta pobiera wskaźnik, a zwraca kod znaku oraz ilość bajtów przez niego zajmowanych;

Wszystko już wiemy, więc można napisać przykładową funkcję, która sprawdzi czy w zadanym łańcuchu znaków znajduje się zadany znak:

uses
  LazUTF8;
 
  function IsLetterInString(const AString, ALetter: String): Boolean;
  var
    LCurrChar, LLastChar: PChar;
    LCharCode, LLetterCode: UInt32;
    LCharLen: Integer;
  begin
    LLetterCode := UTF8CharacterToUnicode(PChar(ALetter), LCharLen);
 
    LCurrChar := @AString[1];
    LLastChar := @AString[Length(AString)];
 
    while LCurrChar <= LLastChar do
    begin
      LCharCode := UTF8CharacterToUnicode(LCurrChar, LCharLen);
 
      if LCharCode = LLetterCode then
        Exit(True);
 
      LCurrChar += LCharLen;
    end;
 
    Result := False;
  end;

Funkcja ta najpierw pobiera kod znaku z argumentu ALetter i zapamiętuje go; Następnie ustawia wskaźnik na pierwszy i statni bajt łańcucha wejściowego (użycie funkcji Length jest celowe!), po czym przystępuje do pętli; W pętli pobierany jest kod znaku, na który wskazuje zmienna LCurrChar, a także jego długość (tutaj dummy); Jeśli kod bieżącego znaku jest równy kodowi szukanego znaku to funkcja przerywa swoje działanie i zwraca True; A jeżeli kod jest inny to wskaźnik LCurrChar inkrementowany jest o tyle bajtów, ile bajtów zajmuje sprawdzany znak - i wracamy do początku pętli; Jeśli znak nie zostanie znaleziony, funkcja zwraca False;

Przykłady wywołania:

Write('Result: ', IsLetterInString('furious programming', 'ą'));  // wypisze w konsoli False
Write('Result: ', IsLetterInString('furiąs programming', 'ą'));   // wypisze w konsoli True
0

Jak zwykle można na Was liczyć. Dzięki wielkie!

P.S.
Jak będzie jakiś zlot 4p to przyjadę tylko po to żeby Wam wszystkim postawić browarka za całą pomoc :)

2

Inna wersja:

uses
  LazUTF8;

function IsLetterInString(const AString, ALetter: string): Boolean;
var
  i, len: Integer;
  s: WideString;
begin
  s:= WideString(AString);
  for i:=1 to Length(s) do
    if (s[i] = WChar(UTF8CharacterToUnicode(PChar(ALetter), len))) then
      Exit(True);
  result:= False;
end;

ewentualnie porównanie można zrobić w ten sposób:

if (Ord(s[i]) = UTF8CharacterToUnicode(PChar(ALetter), len)) then

jeszcze inna wersja porównania:

if UnicodeToUTF8(Ord(s[i])) = ALetter then //to chyba jest najoptymalniejsze

1 użytkowników online, w tym zalogowanych: 0, gości: 1