Jesco: Sonderzeichen in Textdatei Datenbanken (Perl u.a.), No. 2

Hallo,

Ich möchte eine Webanwendung schreiben, die auf eine Datenbank zugreift; diese soll aus einer einfachen Textdatei bestehen, als Programiersprache verwende ich CGI/Perl.

Üblicherweise werden die einzelnen Felder dieser Textdateien mit Pipe oder Raute voneinander getrennt:
zelle1 | zelle2 | ...   oder
zelle1 # zelle2 # ...

Problematisch daran ist, dass man dann diese Trennzeichen selber nicht mehr in den Zellwerten verwenden kann (ausser über Maskierung).

Im Thread:
http://forum.de.selfhtml.org/archiv/2004/2/73163/
hat Christian (Vielen Dank dafür !!) erklärt, dass man als Trennzeichen besser '\036' (Record Separator) dafür verwendet.

Die Datei sieht dann so aus:
zelle11 \036 zelle12 \036 ...  {newline}
zelle21 \036 zelle22 \036 ...  {newline}

Eine Frage bleibt für mich damit aber noch offen: wie soll man den Zeilenumbruch codieren?

Das {newline}-Zeichen würde je nach Betriebssystem "\015\012", "\015" oder "\012" entsprechen und dient dazu die einzelnen Zeilen des Datensatzes zu trennen. Aber wie speichere ich einen Zeilenumbruch innerhalb eines Zellwertes ab? Gibt es dafür auch ein spezielles Zeichen? Ansonsten müsste man innerhalb der Zellwerte wieder zu Maskierung greifen, die ich ja gerade vermeiden will.

Es würde mich freuen, wenn mir jemand helfen könnte.
Gruß,
Jesco

  1. Hi,

    Üblicherweise werden die einzelnen Felder dieser Textdateien mit Pipe oder Raute voneinander getrennt:

    oder Tab oder Semikolon oder Komma oder ...

    Problematisch daran ist, dass man dann diese Trennzeichen selber nicht mehr in den Zellwerten verwenden kann (ausser über Maskierung).

    Richtig.

    Im Thread:
    http://forum.de.selfhtml.org/archiv/2004/2/73163/
    hat Christian (Vielen Dank dafür !!) erklärt, dass man als Trennzeichen besser '\036' (Record Separator) dafür verwendet.

    (Btw: </faq/#Q-19>)

    Egal welches Zeichen man verwendet, es besteht *immer* die Gefahr, dass es im Inhalt vorkommt. *Jedes* Zeichen mit Sonderbedeutung muss maskiert werden. Derer hast Du folgende:

    • Das Zeilen-Trennzeichen (z.B. \n),
    • das Spalten-Trennzeichen (z.B. \t) und infolge dessen
    • das Escape-Zeichen (z.B. ).

    Eine Frage bleibt für mich damit aber noch offen: wie soll man den Zeilenumbruch codieren?

    Wo immer Du eine Maskierung von Zeichen vornehmen musst, triffst Du auf das selbe Prinzip. Du hast ein Escape-Zeichen, welches Du zunächst maskierst, und anschließend maskierst Du alle anderen Zeichen. Immer. Die Dekodierung erfolgt genau umgekehrt.

    Cheatah

    --
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hallo!

      Egal welches Zeichen man verwendet, es besteht *immer* die Gefahr, dass es im Inhalt vorkommt. *Jedes* Zeichen mit Sonderbedeutung muss maskiert werden. Derer hast Du folgende:

      • Das Zeilen-Trennzeichen (z.B. \n),
      • das Spalten-Trennzeichen (z.B. \t) und infolge dessen
      • das Escape-Zeichen (z.B. ).

      Aber der genannte 'Record Separator' (\036) ist doch ein Zeichen, dass im Zellinhalt *nicht* auftaucht. Ich suche jetzt also nur noch ein weiteres Zeichen, das auch im normalen Text nicht auftaucht und das ich somit als Zeilen-Trennzeichen benutzen kann.

      Wo immer Du eine Maskierung von Zeichen vornehmen musst, triffst Du auf das selbe Prinzip. Du hast ein Escape-Zeichen, welches Du zunächst maskierst, und anschließend maskierst Du alle anderen Zeichen. Immer. Die Dekodierung erfolgt genau umgekehrt.

      Vielleicht muss ich dazu erst mal definieren was ich unter 'normalem Text' verstehe. Also im Zellinhalt sollen Buchstaben inkl. Umlaute, Zahlen, Sonderzeichen, Tabs und Zeilenumbrüche vorkommen dürfen. Steuerzeichen wie \036 dagegen nicht. Kann ich unter diesen Umständen nicht auf eine Maskierung verzichten?

      Gruß,
      Jesco

      1. Hi,

        Aber der genannte 'Record Separator' (\036) ist doch ein Zeichen, dass im Zellinhalt *nicht* auftaucht.

        wenn ich den Inhalt einer CSV-Zeile - oder eine ganze CSV-Datei - in einer Spalte einer CSV-Datei speichern möchte, kommt es vor. *Jedes* Zeichen kann vorkommen. Egal wie es heißt.

        Ich suche jetzt also nur noch ein weiteres Zeichen, das auch im normalen Text nicht auftaucht und das ich somit als Zeilen-Trennzeichen benutzen kann.

        Wenn Du über Deine Texte weißt, dass z.B. das Prozentzeichen nicht auftauchen kann(!), oder die Zeichenkette "?foo)", dann steht es Dir frei, diese zu verwenden.

        Vielleicht muss ich dazu erst mal definieren was ich unter 'normalem Text' verstehe. Also im Zellinhalt sollen Buchstaben inkl. Umlaute, Zahlen, Sonderzeichen, Tabs und Zeilenumbrüche vorkommen dürfen.

        Na prima. "Sonderzeichen" umfasst den gesamten Unicode-Raum - mindestens.

        Steuerzeichen wie \036 dagegen nicht. Kann ich unter diesen Umständen nicht auf eine Maskierung verzichten?

        Eine Maskierung nimmt bestimmten Zeichen(ketten) ihre Bedeutung. Wenn diese exakt null mal in einem Text vorkommen, _sind_ sie bereits alle maskiert, auch ohne Dein Zutun. Alle geraden Primzahlen größer als 2 sind Quadratzahlen.

        Cheatah

        --
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
        1. Hallo Cheatah,

          vielen Dank für deine Antworten, ich denke ich sehe da jetzt schon klarer:

          Ist ein bestimmter Zeichenraum (egal ob ASCII oder Unicode) gegeben und in den Zellen der Datensatz-Datei sollen alle diese Zeichen vorkommen dürfen, dann *müssen* notgedrungen für Spalten- und Zeilenseparator Zeichen gewählt werden, die auch in den Zellen vorkommen können. Und dann besteht die *einzige* Möglichkeit darin Maskierungen vorzunehmen. So weit so klar.

          Jetzt hatte ich aber vor mich zu beschränken und einen Teil von Zeichen in den Zellen der Datensatz-Datei *nicht* zu erlauben. Da ich aber keinen guten Überblick über die existierenden Zeichensätze habe, weiss ich nicht welche Zeichen da geeignet wären?! Im Zellinhalt stehen beispielsweise Inhaltsangaben zu technischen Publikationen. Da möchte ich, dass Sonderzeichen wie Gradzeichen, Angstroem, , ¦, ù und Ø vorkommen dürfen. Auf dieses \036-Zeichen dagegen meine ich gut verzichten zu können. Gibt es da nicht ein weiteres Zeichen, das sich als Zeilenumbruchszeichen anbietet?

          Der Grund dafür ist, dass ich es möglichst einfach machen möchte, die Datei auch mit einem einfachen Texteditor bearbeiten zu können. Das erscheint mir schwieriger, wenn ich beim Einfügen von Text eine Reihe von Zeichen maskieren muss - dagegen leichter, wenn ich nur alle Zeilenumbrüche durch ein bestimmtes Zeichen ersetze.

          Wie ist es eigentlich bei Binärdateien gelöst, z.B. in Word? Wird da auch das Prinzip der Zeichenmaskierung eingesetzt?

          Viele Grüße,
          Jesco

          1. Hi,

            vielen Dank für deine Antworten, ich denke ich sehe da jetzt schon klarer:

            tust Du. Deine Zusammenfassung ist veröffentlichungsreif.

            Jetzt hatte ich aber vor mich zu beschränken und einen Teil von Zeichen in den Zellen der Datensatz-Datei *nicht* zu erlauben. Da ich aber keinen guten Überblick über die existierenden Zeichensätze habe, weiss ich nicht welche Zeichen da geeignet wären?!

            Nun, alle im Zeichensatz existierenden bis auf die im Inhalt erlaubten und die bereits verwendeten (also \036 und \012 bzw. ggf. \015).

            Gibt es da nicht ein weiteres Zeichen, das sich als Zeilenumbruchszeichen anbietet?

            Wie wäre es mit dem Tabulator?

            Der Grund dafür ist, dass ich es möglichst einfach machen möchte, die Datei auch mit einem einfachen Texteditor bearbeiten zu können. Das erscheint mir schwieriger, wenn ich beim Einfügen von Text eine Reihe von Zeichen maskieren muss - dagegen leichter, wenn ich nur alle Zeilenumbrüche durch ein bestimmtes Zeichen ersetze.

            Richtig. Eventuell möchtest Du in diesem Satz "Zeichen" durch "Zeichenkette" ersetzen, das könnte die Geschichte noch einfacher machen. Ich wüsste beispielsweise nicht, wie ich ohne mittleren Aufwand mit meinem Texteditor \036 eingeben sollte.

            Wie ist es eigentlich bei Binärdateien gelöst, z.B. in Word?

            Word-Dateien basieren auf XML. Das Verfahren ist übrigens patentiert - arme, kranke Welt.

            Cheatah

            --
            X-Will-Answer-Email: No
            X-Please-Search-Archive-First: Absolutely Yes
            1. tust Du. Deine Zusammenfassung ist veröffentlichungsreif.

              Danke für die Blumen :)

              Wie wäre es mit dem Tabulator?

              Nun, der scheint mir ja nun auch ein häufig vorkommendes Zeichen zu sein. Ich habe jetzt mal in eine ASCII-Tablle geschaut und dort das Zeichen 'Group Separator' (Oktalwert \035) gefunden. Ich schätze dieses Zeichen wird in einem Standardtext genau so wenig auftauchen wie \036.

              Richtig. Eventuell möchtest Du in diesem Satz "Zeichen" durch "Zeichenkette" ersetzen, das könnte die Geschichte noch einfacher machen. Ich wüsste beispielsweise nicht, wie ich ohne mittleren Aufwand mit meinem Texteditor \036 eingeben sollte.

              Nun, ich verwende den Editor WinEdt (http://www.winedt.com/). Der stellt freundlicherweise Steuerzeichen wie \035 und \036 nicht alle als Kästchen dar sondern farbig unterlegt und voneinander unterscheidbar. Ich kopiere dann einfach das \035-Zeichen aus dem Datensatz (irgendwo taucht es schon auf) und mache einen Suchlauf im neu einzufügenden Text: in den Ersetzen-String kopiere ich das Zeichen per Copy&Paste, der Finden-String lautet '>' (> entspricht Zeilenumbruch, bei RegEx). Danach kann ich den String in den Datensatz kopieren.

              Wie ist es eigentlich bei Binärdateien gelöst, z.B. in Word?

              Word-Dateien basieren auf XML. Das Verfahren ist übrigens patentiert - arme, kranke Welt.

              Wenn ich das dann richtig verstehe wird dann bei Word also auch eine Maskierungstechnik angewandt?!

              Ich habe jetzt zwei CGI-Scripte geschrieben, die meiner Aufgabe schon recht nahe kommen und zitiere die wichtigen Stellen (wenn jemand das komplette Script sehen möchte, poste ich es auch gern):

              CGI-Script zum Schreiben:
              ...
              my $inputString = "Zeile1\nZeile2\036Zeile2\nZeile3";  # Beispiel für Text
              $inputString =~ s/\035//g;   # Verwenden von \035 ist verboten -> wird einfach gelöscht
              $inputString =~ s/\036//g;   # Verwenden von \036 ist verboten -> wird einfach gelöscht
              $inputString =~ s/\n/\035/g;   # Ersetzen von Zeilenumbrüchen durch \035
              ...
              print DATEI "Zelle 11\036$inputString\036Zelle 13\036\n";   #Schreibe Daten
              ...

              CGI-Script zum Auslesen:
              ...
              open (FileHandler, "$argDataFile") || &print_table_not_found();
                  foreach(<FileHandler>)
                  {
                    my @entrydata;
                    @entrydata = split('\036', $_);
              ...
                    $cellValue=$_;
                    $cellValue =~ s/\035/<br>/g;   #replace \035 with linebreak
              ...

              Als 'linebreak' ist für die Darstellung in HTML <br> sinnvoll, aber natürlich kann man hier auch \n verwenden.

              Gruß,
              Jesco

              1. Hi,

                tust Du. Deine Zusammenfassung ist veröffentlichungsreif.
                Danke für die Blumen :)

                Ehre, wem Ehre gebührt.

                Wie wäre es mit dem Tabulator?
                Nun, der scheint mir ja nun auch ein häufig vorkommendes Zeichen zu sein. Ich habe jetzt mal in eine ASCII-Tablle geschaut und dort das Zeichen 'Group Separator' (Oktalwert \035) gefunden. Ich schätze dieses Zeichen wird in einem Standardtext genau so wenig auftauchen wie \036.

                Beides, also ob der Tabulator vorkommt und wie dem bei \035 ist, musst Du _wissen_, nicht vermuten.

                Nun, ich verwende den Editor WinEdt (http://www.winedt.com/). Der stellt freundlicherweise Steuerzeichen wie \035 und \036 nicht alle als Kästchen dar sondern farbig unterlegt und voneinander unterscheidbar.

                Danke für den Tipp. Ich verwende TextPad (http://www.textpad.com/), mit dem ich zwar im Prinzip sehr zufrieden bin, der aber in mancherlei Detail noch ausbaufähig ist.

                (> entspricht Zeilenumbruch, bei RegEx).

                Oh, faszinierend. Was für ein RegExp-Modell ist das denn? Normalerweise sollte man mit \n o.ä. erfolgreicher sein ...

                Wenn ich das dann richtig verstehe wird dann bei Word also auch eine Maskierungstechnik angewandt?!

                Eigentlich überall und immer. Ausnahmen machen nur Ausnahmefälle, wie etwa der Deine.

                $inputString =~ s/\035//g;   # Verwenden von \035 ist verboten -> wird einfach gelöscht

                Auch 'ne Variante :-)

                open (FileHandler, "$argDataFile") || &print_table_not_found();

                Bei Funktionen sollte die öffnende Klammer direkt an den Funktionsnamen anschließen,

                foreach(<FileHandler>)

                anders als bei Entscheidungslogik wie "if" oder "foreach" :-) Gibt Deine sub print_table_not_found den Wert von $! irgendwo aus?

                my @entrydata;
                      @entrydata = split('\036', $_);

                @entrydata solltest Du mit einem Leerarray initialisieren; entweder bei der Deklaration, oder beim split() als "|| ()".

                Cheatah

                --
                X-Will-Answer-Email: No
                X-Please-Search-Archive-First: Absolutely Yes
                1. Hallo,

                  Beides, also ob der Tabulator vorkommt und wie dem bei \035 ist, musst Du _wissen_, nicht vermuten.

                  Na, das ist schon klar, aber daher präziser formuliert: \035 und \036 kommen in meinen Inhalten nicht vor.

                  Oh, faszinierend. Was für ein RegExp-Modell ist das denn? Normalerweise sollte man mit \n o.ä. erfolgreicher sein ...

                  WinEdt hat ein paar Eigenheiten bei seinen RegEx. Es ist im übrigen ein Editor der ziemlich spezialisiert auf TeX/LaTeX ist - aber auch sonst ein paar sinnvolle Features hat.

                  Danke für die Programmierhinweise, werde ich bei der Endversion auch berücksichtigen, das hatte ich halt schnell runtergetippt.

                  Ciao,
                  Jesco