[gelöst] Umlaute (wieder einmal )

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Aliobaba
Lazarusforum e. V.
Beiträge: 496
Registriert: Di 1. Mai 2012, 09:11

[gelöst] Umlaute (wieder einmal )

Beitrag von Aliobaba »

Hallo,

ich weiß ja, wie peinlich das ist - aber die Umlaute bringen mich zur Verzweiflung :(

Aus einem String möchte ich gerne Sonderzeichen herausfiltern. Und ich kriegs einfach nicht hin: Auch die Umlaute werden dauernd herausgefiltert :(
Vielleicht ist ja jemand nochmal geduldig.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
a,b :string;
begin
  a := edit1.text;
  b := Check_String( a );
// b := GetOnly (a);    //alternativ, funktioniert aber auch nicht!
  edit2.Text:= b;
end;
 

Code: Alles auswählen

function Check_String(Text : String) : string;    //verbotene Buchstaben rausfiltern!!
var
  i : integer;
begin
  Result := '';
  for i:=1 to Length(Text) do
  begin
    if ( Text[i] in [  char(#46), char(#48)..char(#57), char(#65)..char(#90), char(#97)..char(#122) ,  char(#196),char(#214),char(#220),char(#228),char(#246), char(#252)  ] ) then
      begin
        Result := Result + Text[i];
      end;
  end;
end;

Code: Alles auswählen

function GetOnly(Value: String): String;
var
  i, CurResult: Integer;
begin
  SetLength(Result, Length(Value));
  CurResult := 1;
  for i := 1 to Length(Value) do
    if Value[i] in ['a'..'z', 'A'..'Z' , '0'..'9' , 'ä','ö','ü','Ä','Ö','Ü'  ] then   //funktioniert, wenn die Umlaute nicht dabei sind
    begin
      Result[CurResult] := Value[i];
      Inc(CurResult);
    end;
  SetLength(Result, CurResult - 1);
end;      
 
Alles mögliche habe ich schon probiert: (SystoUTF8, UTF8Decode, UTF8toAnsi usw.)
Wo liegt der Haken, kann/mag mir jemand helfen?

Aliobaba
Zuletzt geändert von Aliobaba am Mi 4. Nov 2015, 21:09, insgesamt 1-mal geändert.
"MyMemoryDB" ( https://www.heise.de/download/product/mymemorydb-89626 )

Mathias
Beiträge: 6918
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Umlaute (wieder einmal )

Beitrag von Mathias »

Um was für Sonderzeichen handelt es sich, wen es sich nur um die gewöhnlichen Zeichen handelt, ist es vielleicht einfacher diese zu filtern anstelle der Buchstaben.

Unter Windows könnt noch UTFtoConsole funktionieren.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 5152
Registriert: Fr 8. Apr 2011, 09:01

Re: Umlaute (wieder einmal )

Beitrag von wp_xyz »

Falls du in dem Edit-Control nur Zeichen aus der System-CodePage verwendest, geht es am einfachsten, indem du den Text von UTF-8 (weil er in einem LCL-Control steht) nach Ansi wandelt, die Prüfung machst und dann wieder nach UTF-8 zurückkonvertierst:

Code: Alles auswählen

 
function Check_String(Text : String) : string;    //verbotene Buchstaben rausfiltern!!
var
  i : integer;
begin
  Text := UTF8ToAnsi(Text);  // ab hier ist jedes Zeichen 1 Byte lang, vorher nicht !!!
  Result := '';
  for i:=1 to Length(Text) do
    if (Text[i] in [char(#46), char(#48)..char(#57), char(#65)..char(#90), char(#97)..char(#122) ,          
                    char(#196),char(#214),char(#220),char(#228),char(#246), char(#252)] ) 
    then 
       Result := Result + Text[i];
  Result := AnsiToUTF8(Result);
end;
 
function GetOnly(Value: String): String;
var
  i, CurResult: Integer;
begin
  Value := UTF8ToAnsi(Value);
  SetLength(Result, Length(Value));
  CurResult := 1;
  for i := 1 to Length(Value) do
    if Value[i] in ['a'..'z', 'A'..'Z' , '0'..'9' , 'ä','ö','ü','Ä','Ö','Ü'  ] then  
    begin
      Result[CurResult] := Value[i];
      Inc(CurResult);
    end;
  SetLength(Result, CurResult - 1);
  Result := AnsiToUtf8(Result);
end;      
 
Oder, wenn du nicht den Umweg über die Systemcodepage machen willst, musst du den String nicht byteweise (denn "Length()" ergibt die Anzahl der Bytes, nicht die der Zeichen) durchlaufen, sondern zeichenweise. Wichtig: In der Prüfung auf, z.B., 'ä' nicht #228 schreiben, denn letzteres ist nur 1 byte, aber 'ä' hat in UTF8 zwei:

Code: Alles auswählen

 
uses
  LazUtf8;
 
function CheckText(AText: String): String;
var
  p: PChar;
  ch: Cardinal;
  L, n: Integer;
begin
  Result := '';
  if AText = '' then exit;
 
  p := @AText[1];
  while p^ <> #0 do begin
    ch := UTF8CharacterToUnicode(p, L);
    case UniCodeToUTF8(ch) of
      'ä', 'ö', 'ü', '€' : ;     // diese Zeichen ausfiltern
      else Result := Result + UnicodeToUtf8(ch);
    end;
    inc(p, L);
  end;
end;

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Umlaute (wieder einmal )

Beitrag von Michl »

Den Umweg über Ansi würde ich nicht gehen, das kann einem in einem anderen Land mit einer anderen SystemCodepage auf die Füße fallen.

Ab FPC 3.0.0 ist es sogar erstmals möglich reine AnsiCodePage Programme zu erstellen http://wiki.freepascal.org/Lazarus_with ... UTF-8_mode. Man sollte aber wirklich wissen, was man da tut. Ohne driftigen Grund würde ich nicht auf die UTF8 Annehmlichkeiten verzichten. Weitere Infos über die neuen Strings: http://wiki.freepascal.org/Better_Unico ... in_Lazarus

Für dein Problem kann dir neben der letzten Methode von wp auch das helfen: http://wiki.freepascal.org/UTF8_strings ... characters

PS: theo hatte auch mal einen Iterator für UTF8 geschrieben siehe: http://www.lazarusforum.de/viewtopic.php?f=29&t=5894

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Umlaute (wieder einmal )

Beitrag von TBug »

Wie wäre es denn mit einem siplen und anfängerfreudlichem StringReplace?

Code: Alles auswählen

 
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
uses
  StrUtils;
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
var
  lDelChars : array [1..3] of string = ('ä','ö','ß');
  liZ1: Integer;
  lString: String;
begin
  lString := Edit1.Text;
  for liZ1 := 1 to Length(lDelChars) do
   begin
    lString := StringReplace(lString,lDelChars[liZ1],'',[rfReplaceAll,rfIgnoreCase]);
   end;
 
  Edit2.Text := lString;
end;
 
end.  
 

.

Aliobaba
Lazarusforum e. V.
Beiträge: 496
Registriert: Di 1. Mai 2012, 09:11

Re: Umlaute (wieder einmal )

Beitrag von Aliobaba »

Hallo,

vielen herzlichen Dank für Eure schnellen Antworten!

es geht darum, dass ich Texte abspeichern möchte und die Überschriften dieser Texte - die ja schon vorhanden sind, weshalb ich diese bei der Eingabe nicht mehr filtern kann [trotzdem Danke! @Mathias] - in den File-Namen übernehmen möchte:

Beispiel:
Schwäche des Dollars ab 100$ nicht mehr zu ertragen (ist die Überschrift)
..... Dann ein beliebiger Text......

In so einem File-Namen stören natürlich die Leerzeichen (ist kein Problem -> zu ersetzen mit Unterstrich), die Umlaute sollten vorhanden sein , aber diese Sonderzeichen (hier im Beispiel: "$") sind ein Problem; deshalb müssen die weg.

In meinem Beispiel möchte ich die "normalen" Zeichen (=Zahlen und Buchstaben UND(!) Umlaute ) erhalten und alle anderen Zeichen rausfiltern. Mein Weg war, deshalb alle "gewünschten Zeichen" zuzulassen (ist übersichtlicher als "verbotene Zeichen" wegzufiltern, da dabei manche Zeichen "vergessen" werden könnten.

Und da war mein Problem: Die Umlaute wurden - obwohl ich sie zulassen wollte - schlicht ignoriert und erschienen nicht im Edit2.txt.

Die zwei ersten Beispiele von "wp_xyz" brachten mir keine Hilfe: Die Umlaute wurden weiterhin nicht übernommen, fehlten also im "Edit2-Feld"
Ansi_1.png
Ansi_1.png (5.17 KiB) 2824 mal betrachtet
und im zweiten Beispiel "getonly" schimpfte der Compiler bei den Buchstaben "ä","ö" -> Ordinal expression expected.

Die "Checktext" Funktion von "wp_xyz" bringt die Lösung. Vielen Dank!!
Ansi_2.png
Ansi_2.png (5.8 KiB) 2824 mal betrachtet
Die Umlaute werden dargestellt und können bei Bedarf auch gefiltert werden, leider sieht man auch eine Fülle von Sonderzeichen, die man zwar einzeln rausfiltern kann, von denen man aber keines vergessen darf.
Perfekt wäre es halt, wenn man die Buchstaben, die man möchte, zulassen könnte, statt die, die man nicht möchte ausschließen muss. (wäre eben irgendwie sicherer, dass man nichts vergisst)

Geht sicher, aber ich habe mit den Zeichen "@" und "p" mit dem Hütchen und somit mit dem Code erhebliche Verständnisschwierigkeiten (Ist schon mehr als Lektion2 und deshalb für mich sehr schwierig zu verstehen).

Könntest Du mir da nochmal helfen?

Aliobaba
"MyMemoryDB" ( https://www.heise.de/download/product/mymemorydb-89626 )

Aliobaba
Lazarusforum e. V.
Beiträge: 496
Registriert: Di 1. Mai 2012, 09:11

Re: Umlaute (wieder einmal )

Beitrag von Aliobaba »

... Uups; das mit dem StringReplace werde ich noch ausprobieren (Antwort kam während ich geschrieben habe)
Danke erstmal!, TBug!
"MyMemoryDB" ( https://www.heise.de/download/product/mymemorydb-89626 )

wp_xyz
Beiträge: 5152
Registriert: Fr 8. Apr 2011, 09:01

Re: Umlaute (wieder einmal )

Beitrag von wp_xyz »

Also ich verstehe die Fragestellung mal wieder überhaupt nicht: Warum willst du denn ein $-Zeichen aus einem Dateinamen entfernen? Ist doch erlaubt. Auch ein Leerzeichen ist heutzutage im Dateinamen erlaubt, auch Umlaute. Nicht erlaubt wären dagegen Zeichen wie *, ", /, \ etc. Aber diese wiederum sind in UTF8 und Ansi dieselben, so dass sie von deinem anfangs vorgestellten Code richtig entfernt werden könnten.

Unter diesem Gesichtspunkt ist die Aufgabe nicht, Zeichen zuzulassen, sondern Zeichen zu entfernen, weil *alle* Zeichen in einem Dateinamen erlaubt sind, bis auf die wenigen Ausnahmen.

Aliobaba
Lazarusforum e. V.
Beiträge: 496
Registriert: Di 1. Mai 2012, 09:11

Re: Umlaute (wieder einmal )

Beitrag von Aliobaba »

Hallo,

@TBug: Also, dieser Code funktioniert ebenfalls sehr gut - und ich verstehe ihn auch 8) . Dass es diesen Befehl gibt, wusste ich, aber dass man ein Array verwenden kann, wusste ich nicht: Toll, danke!

@wp_xyz: Mein anfangs vorgestellter Code war deshalb nicht geeignet, weil er die Umlaute nicht übernommen hat (sh. Bild) "ä, ö, ü" sind verschwunden. Mit den "erlaubten" Zeichen hast Du natürlich recht. Ich möchte da aber ein wenig restriktiver sein, damit auch ältere Systeme mit den Dateinamen noch zurecht kommen. Diese großen Freiheiten machen ja auch heutzutage immer wieder Probleme, wenn man zwischen Linux- und (älteren?) Windows-Systemen umkopiert "Konnte nicht kopiert werden...".

Außerdem hätte ich gerne ein Tool (evtl. für andere Zwecke irgendwann einmal), mit dem ich wirklich nur eine recht begrenzte Anzahl von Zeichen zulassen kann. Dies wäre dann einfacher, als alle möglichen (und "unmöglichen" - also sehr seltenen) Zeichen dezidiert ausschließen zu müssen.

Jemand eine Idee?

Viele Grüße!
Aliobaba
"MyMemoryDB" ( https://www.heise.de/download/product/mymemorydb-89626 )

wp_xyz
Beiträge: 5152
Registriert: Fr 8. Apr 2011, 09:01

Re: Umlaute (wieder einmal )

Beitrag von wp_xyz »

Und dann ist noch das Problem, wo die Strings, die du bearbeiten willst, herkommen. Wurden die irgendwann einmal eingetippt? Dann sind sie UTF8. Oder stammen sie aus irgendwelchen Dateien? Dann ist alles möglich, und dein Verfahren muss zuerst die Zeichenkodierung erkennen und vereinheitlichen.

Und noch ein Punkt: Was passiert, wenn zunächst unterschiedliche Strings nach deiner Behandlung zum selben Dateinamen führen?

Und wie ist es mit der Länge des Dateinamens? Ich weiß nicht, ob du DOS und Windows 3.1 (weil du von "älteren" Windowsversionen redest) noch erlebt hast: da gab's nur 8. Bei aktuelleren Windows-Versionen weiß ich gar nicht, manchmal lese ich 260 Zeichen, manchmal 1024 - für den ganzen Pfad, das kann bei verschachtelten Verzeichnissen bald zusammenkommen.

Ich finde, du sollest dir zunächst über die genauen Anforderungen klarwerden. Das Weglassen/Ersetzen von Zeichen ist das kleinste Problem. Hier hast du eine Routine, in der statt wie oben Zeichen wegzulassen, nur erlaubte Zeichen verwendet werden. Funktioniert für UTF8.

Code: Alles auswählen

 
uses
  LazUtf8;
 
const
  AllowedChars: String =
    'abcdefghihklmnopqrstuvwxyzäöü' +
    'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ' +
    '0123456789';
 
function CheckText(AText: String): String;
var
  p: PChar;
  ch: string;
  L: Integer;
begin
  Result := '';
  if AText = '' then exit;
 
  p := @AText[1];
  while p^ <> #0 do begin
    ch := UnicodeToUtf8(UTF8CharacterToUnicode(p, L));
    if UTF8Pos(ch, AllowedChars) > 0 then
      Result := Result + ch;
    inc(p, L);
  end;
end; 

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Umlaute (wieder einmal )

Beitrag von TBug »

Aliobaba hat geschrieben: Geht sicher, aber ich habe mit den Zeichen "@" und "p" mit dem Hütchen und somit mit dem Code erhebliche Verständnisschwierigkeiten (Ist schon mehr als Lektion2 und deshalb für mich sehr schwierig zu verstehen).
Schau in der Hilfe oder google einmal nach "Pointer" und "dereferenzieren"!


.

Aliobaba
Lazarusforum e. V.
Beiträge: 496
Registriert: Di 1. Mai 2012, 09:11

Re: Umlaute (wieder einmal )

Beitrag von Aliobaba »

...tja, da ist noch viel zu lernen. Aber für mein Problem habe ich jetzt erstmal ein Lösung:
:D https://www.youtube.com/watch?v=2Fp4A6idTuE 8)

Vielen, vielen Dank!!

Aliobaba
"MyMemoryDB" ( https://www.heise.de/download/product/mymemorydb-89626 )

Antworten