none
IndexOf RRS feed

  • Frage

  • Hallo! Ich habe den Text eines PDF-Dokumentes ausgelesen (itextsharp). in dem ausgelesen string gibt es auch Beträge in Euro. Für 123 € und 456 € bekomme ich folgenden string:

    123,00 ? 123,00 ?

    Wenn ich mit IndexOf den string nach "?" durchsuche bekomme ich als Index den Wert -1.  Warum ist das so? Bei dem Fragezeichen handelt es sich wirklich um das Fragezeichen (hexadezimal 63). Was mache ich falsch? Auch die Suche nach "\r\n" gestaltet sich schweirig ;)

    Danke für die Hilfe!

     

     

    Dienstag, 1. Februar 2011 18:09

Antworten

  • Hallo D.,

    wenn Deine Frage quasi folgendermassen interpretiert wird, käme nicht -1 heraus, sondern 7:

       string s = "123,00 ? 123,00 ?";
       int position = s.IndexOf("?");
       MessageBox.Show(position.ToString()); // == 7 [OK]
    

    Gut, das Fragezeichen ist !dezimal! 63 (nicht hexadezimal), aber wahrscheinlich hast Du das ja auch gemeint.
    Also muss noch etwas mit dem Original-String - den itextSharp erzeugt hat- oder Du aus der Debugger-Anzeige evtl. nur so lesen konntest - im argen sein.

    Kannst Du mal posten, wie der String in Bytes aussieht?

       string s = <Dein ITextSharp String>;
       byte[] bytes = Encoding.Unicode.GetBytes(s);
       string byteStringZumPosten= string.Join(",", bytes);
    


    by the way, wenn ich mal folgenden Code in einem Test ausführe, erkennt er auch die € Zeichen (ohne daraus ein ? zu machen) :

    using System;
    using System.Windows.Forms;
    using iTextSharp.text.pdf.parser;
    using iTextSharp.text.pdf; // http://sourceforge.net/projects/itextsharp/
    
    namespace WinItextSharpString
    {
      public partial class Form1 : Form
      {
        public Form1() {InitializeComponent();}
    
        string pdfDatei = "Beispiel.pdf";
    
        private void Form1_Load(object sender, EventArgs e)
        {
          PdfReader pdfReader = new PdfReader(pdfDatei);
          string text = PdfTextExtractor.GetTextFromPage(pdfReader, 1);
          int position = text.IndexOf("€");
          MessageBox.Show(position.ToString()); // == 14
        }
      }
    }
    

    Der iTextSharp-PdfReader hat ja auch noch einige Codierungs-Optionen ....


    ciao Frank

    • Bearbeitet Frank Dzaebel Dienstag, 1. Februar 2011 19:27
    • Als Antwort markiert DulcineaS Mittwoch, 2. Februar 2011 17:21
    Dienstag, 1. Februar 2011 19:01
  • Hallo Dulcinea,

    Dein String ist wahrscheinlich Unicode-kodiert:

    byte[] textBytes = new byte[] {49,0,49,0,50,0,44,0,52,0,50,0,32,0,128,0,32,0,57,0,56,0,44,0,57,0,50,0,32,0,10,0,13,0,128,0,32,0,53,0};
    string text = Encoding.Unicode.GetString(textBytes);
    
    

    Gruss
    Marcel

    Dienstag, 1. Februar 2011 20:46
    Moderator
  • Hallo D.,

    > Danke für alle Tips! [...] Die Zeichnekette war Unicode-kodiert. Der umständliche Weg funktioniert jetzt auch.

    Gerne. Aber es muss nicht unbedingt umständlich sein:

    byte[] textBytes = new byte[] 
    {
    	49,0, //0: 1
    	49,0, //1: 1
    	50,0, //2: 2
    	44,0, //3: ,
    	52,0, //4: 4
    	52,0, //5: 2
    	32,0, //6: blank
    	128,0 //7: €
    };
    
    string unicodeString = Encoding.Unicode.GetString(textBytes); // Dein String
    int index = unicodeString.IndexOf((char)128);
    

    Ganz einfach.

    Nachtrag: Das Problem mit dem €-Zeichen und IndexOf wäre gar nicht erst aufgetreten, wenn die Unicode-kodierte Zeichenfolge das €-Zeichen korrekt kodiert hätte. Aber statt € als U+20AC zu kodieren, wurde das Zeichen in der Originalzeichenfolge als ANSI kodiert (0x80[128]). Da in diesem Unicode-Codebereich (128-159) nur nichtdruckbare Controlzeichen definiert sind, kann das so nicht funktionieren.

    Es ist also kein Wunder, wenn unicodeString.IndexOf("€") den Wert -1 zurückgibt, denn \u20ac ist ja im String tatsächlich nicht vorhanden. Deshalb sucht der obige Code nach (char)128 ... und findet natürlich das Zeichen. Die zurückgegebene Zeichenfolge weist auch weitere Ungereimtheiten auf, z.B. statt \r\n steht da \n\r, was natürlich die Suche nach CRLF von vornherein vereitelt. Sehr wahrscheinlich ein Fehler beim Erstellen des PDF-Dokuments.

     

     

     


    Gruss
    Marcel

    Dienstag, 1. Februar 2011 22:43
    Moderator

Alle Antworten

  • Hi,

    String.IndexOf( <Char> ) sucht nach einem Unicode Zeichen. Bist Du sicher, dass der Inhalt des PDFs bei dir durch das passende Encoding auch als Unicode ankommt? Falls nicht, solltest Du mal String.IndexOf( <String> ) oder gar String.IndexOf( <String>, <StringComparison ) probieren.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Dienstag, 1. Februar 2011 19:00
    Moderator
  • Hallo D.,

    wenn Deine Frage quasi folgendermassen interpretiert wird, käme nicht -1 heraus, sondern 7:

       string s = "123,00 ? 123,00 ?";
       int position = s.IndexOf("?");
       MessageBox.Show(position.ToString()); // == 7 [OK]
    

    Gut, das Fragezeichen ist !dezimal! 63 (nicht hexadezimal), aber wahrscheinlich hast Du das ja auch gemeint.
    Also muss noch etwas mit dem Original-String - den itextSharp erzeugt hat- oder Du aus der Debugger-Anzeige evtl. nur so lesen konntest - im argen sein.

    Kannst Du mal posten, wie der String in Bytes aussieht?

       string s = <Dein ITextSharp String>;
       byte[] bytes = Encoding.Unicode.GetBytes(s);
       string byteStringZumPosten= string.Join(",", bytes);
    


    by the way, wenn ich mal folgenden Code in einem Test ausführe, erkennt er auch die € Zeichen (ohne daraus ein ? zu machen) :

    using System;
    using System.Windows.Forms;
    using iTextSharp.text.pdf.parser;
    using iTextSharp.text.pdf; // http://sourceforge.net/projects/itextsharp/
    
    namespace WinItextSharpString
    {
      public partial class Form1 : Form
      {
        public Form1() {InitializeComponent();}
    
        string pdfDatei = "Beispiel.pdf";
    
        private void Form1_Load(object sender, EventArgs e)
        {
          PdfReader pdfReader = new PdfReader(pdfDatei);
          string text = PdfTextExtractor.GetTextFromPage(pdfReader, 1);
          int position = text.IndexOf("€");
          MessageBox.Show(position.ToString()); // == 14
        }
      }
    }
    

    Der iTextSharp-PdfReader hat ja auch noch einige Codierungs-Optionen ....


    ciao Frank

    • Bearbeitet Frank Dzaebel Dienstag, 1. Februar 2011 19:27
    • Als Antwort markiert DulcineaS Mittwoch, 2. Februar 2011 17:21
    Dienstag, 1. Februar 2011 19:01
  • Hallo, ja ich sollte mich um das encoding kümmern..

    Aber hier der byteStringzumPsoten:

     

    "49,0,49,0,50,0,44,0,52,0,50,0,32,0,128,0,32,0,57,0,56,0,44,0,57,0,50,0,32,0,10,0,13,0,128,0,32,0,53,0"

    Dienstag, 1. Februar 2011 19:20
  • Hallo Dulcinea,

    Dein String ist wahrscheinlich Unicode-kodiert:

    byte[] textBytes = new byte[] {49,0,49,0,50,0,44,0,52,0,50,0,32,0,128,0,32,0,57,0,56,0,44,0,57,0,50,0,32,0,10,0,13,0,128,0,32,0,53,0};
    string text = Encoding.Unicode.GetString(textBytes);
    
    

    Gruss
    Marcel

    Dienstag, 1. Februar 2011 20:46
    Moderator
  • Danke für alle Tips! Mit PdfTextExtractor erspart man sich einiges an Umwandlungen ;)

    Die Zeichnekette war Unicode-kodiert. Der umständliche Weg funktioniert jetzt auch.

    Noch einmal vielen  Dank!

    Dienstag, 1. Februar 2011 21:01
  • Hallo D.,

    > Danke für alle Tips! [...] Die Zeichnekette war Unicode-kodiert. Der umständliche Weg funktioniert jetzt auch.

    Gerne. Aber es muss nicht unbedingt umständlich sein:

    byte[] textBytes = new byte[] 
    {
    	49,0, //0: 1
    	49,0, //1: 1
    	50,0, //2: 2
    	44,0, //3: ,
    	52,0, //4: 4
    	52,0, //5: 2
    	32,0, //6: blank
    	128,0 //7: €
    };
    
    string unicodeString = Encoding.Unicode.GetString(textBytes); // Dein String
    int index = unicodeString.IndexOf((char)128);
    

    Ganz einfach.

    Nachtrag: Das Problem mit dem €-Zeichen und IndexOf wäre gar nicht erst aufgetreten, wenn die Unicode-kodierte Zeichenfolge das €-Zeichen korrekt kodiert hätte. Aber statt € als U+20AC zu kodieren, wurde das Zeichen in der Originalzeichenfolge als ANSI kodiert (0x80[128]). Da in diesem Unicode-Codebereich (128-159) nur nichtdruckbare Controlzeichen definiert sind, kann das so nicht funktionieren.

    Es ist also kein Wunder, wenn unicodeString.IndexOf("€") den Wert -1 zurückgibt, denn \u20ac ist ja im String tatsächlich nicht vorhanden. Deshalb sucht der obige Code nach (char)128 ... und findet natürlich das Zeichen. Die zurückgegebene Zeichenfolge weist auch weitere Ungereimtheiten auf, z.B. statt \r\n steht da \n\r, was natürlich die Suche nach CRLF von vornherein vereitelt. Sehr wahrscheinlich ein Fehler beim Erstellen des PDF-Dokuments.

     

     

     


    Gruss
    Marcel

    Dienstag, 1. Februar 2011 22:43
    Moderator
  • Hallo D.,

    • > Danke für alle Tips! Mit PdfTextExtractor erspart man sich einiges an Umwandlungen ;)


    schön, dass freut mich.

    • > Die Zeichenkette war Unicode-kodiert.

    also, mal ganz grundlegend. Zeichenketten (also Typ string) ist in .NET immer UTF-16, also mit (Encoding.Unicode) codiert!
    Was nur zum Beispiel unterschiedlich ist, sind Interpretationen von Bytes-Streams/Listen.  

    Aber wenn es jetzt mit dem von mir genannten PdfTextExtractor so gut geklappt hat, dann haben wir ja die Lösung.
    Dann können wir die Frage hier abschliessen.


    ciao Frank
    • Als Antwort markiert DulcineaS Mittwoch, 2. Februar 2011 17:21
    • Tag als Antwort aufgehoben DulcineaS Mittwoch, 2. Februar 2011 17:21
    Mittwoch, 2. Februar 2011 06:19
  • Hallo Marcel,

    • > Es ist also kein Wunder, wenn unicodeString.IndexOf("€") den Wert -1 zurückgibt,

    sie hat doch gar nicht nach "€" abgefragt, das hast Du evtl. mit meinem Posting gemischt. In meinem Posting kann ich nach "€" abfragen, weil durch den PdfTextExtractor standardmäßig korrekt umgewandelt wird.
    Sie hatte ja den String "123,00 ? 123,00 ?" und fragte deswegen natürlich nach "?" ab, nicht nach "€".

    Aber ich denke, sie hat ja das schon lange durch den von mir genannten PdfTextExtractor lösen können, sodass man auch das Encoding nicht mehr anpassen muss.


    ciao Frank
    Mittwoch, 2. Februar 2011 13:37
  • Hallo Frank,

    Frank schrieb:

    sie hat doch gar nicht nach "€" abgefragt [...]

    Dulcineea schrieb:

    Für 123 € und 456 € bekomme ich folgenden string [...] Wenn ich mit IndexOf den string nach "?" durchsuche bekomme ich als Index den Wert -1.  Warum ist das so?

    Da das Encoding von €  - wie beschrieben - falsch ist, können weder "€" noch der Fallback-Platzhalter "?" im String gefunden werden. Wenn Du willst, erklär ich das ausführlicher, damit auch wirklich alle es verstehen.

    Frank schrieb:

    Aber ich denke, sie hat ja das schon lange durch den von mir genannten PdfTextExtractor lösen können, sodass man auch das Encoding nicht mehr anpassen muss.

    Die Art und Weise wie der String kodiert ist, ist schlicht und ergreifend falsch. Dort wird Unicode mit ANSI-Kodierung vermischt. Ich kann mir nicht vorstellen, dass es ein Tool geben kann, das aus so gemischten Bytes was sinnvolles herauslesen kann. Kannst Du das? Welches wäre denn die theoretische Grundlage dafür, dass man die Byteabfolge {128, 0} als € in einer Unicode-Zeichenfolge interpretieren kann. Bei allem Respekt.

    Gruss
    Marcel

    Mittwoch, 2. Februar 2011 14:13
    Moderator
  • Marcel,

           > sie schreibt [...]

    tatsächlich schreibt sie:
             "Für 123 € und 456 € bekomme ich folgenden string:  123,00 ? 123,00 ?"
    und daran erkennst Du, dass das "€" im Original PDF ist und nicht im String.
    IndexOf("€") hat sie ja nicht gemacht (wie Du schreibst), sondern nur IndexOf("?") -> das ergibt -1.

          > Die Art und Weise wie der String kodiert ist, ist schlicht und ergreifend falsch.

    Zur Sicherheit - string's sind in .NET immer UTF-16. Du kannst sie nicht "falsch" codieren.
    Bei Encoding-Erkennung geht es eher um Byte-Streams Interpretation.
    Wie gesagt, der PdfTextExtractor macht das wirklich 100% richtig.


          > Byteabfolge {128, 0} als €

    "Encoding.Default" kann zumindestens den Euro erkennen und man würde mit dem StreamWriter einen lesbaren Text mit "€" und den Werten (in UTF-8) bekommen. Aber letztlich ist das ja nicht relevant (der iTextSharp kann viele auch seltene Encodings).

    Die richtige Methode ist hier halt, den von mir genannten PdfTextExtractor zu benutzen, aber das wurde ja auch schon lange erkannt, denn eine umständlich Decodierung ist dann nicht notwendig.
    Da sollten wir dann auch enden.

    EOT
    • Bearbeitet Frank Dzaebel Mittwoch, 2. Februar 2011 16:35 EOT eingefuegt
    Mittwoch, 2. Februar 2011 15:47
  • Frank,

    > Frank schrieb: "tatsächlich schreibt sie: 'Für 123 € und 456 € bekomme ich folgenden string:  123,00 ? 123,00 ?' und daran erkennst Du, dass das € im Original PDF ist und nicht im String."

    Entschuldige dass ich eins und eins zusammenzähle. Hat sie nicht auch geschrieben, dass ihr String folgende Bytes enthält? 

    49,0,49,0,50,0,44,0,
    52,0,50,0,32,0,128,0,
    32,0,57,0,56,0,44,0,
    57,0,50,0,32,0,10,0,
    13,0,128,0,32,0,53,0

    Siehst Du darin irgendwelche Fragezeichen? Ich auch nicht. Die Fragezeichen sind ein Resultat eines Fallbacks, und {128} entpricht dem Eurozeichen im ANSI-Mapping das hierzulande verwendet wird. Die Null dahinter macht das ganze Unicode-kompatibel, aber auch nicht mehr, denn die eigtl. Kodierung ist U+20AC. Will sagen, interpretiert man 128 auf einem russischen System (andere Codepage) erlebt man seine Überraschung, während das Unicode €-Zeichen auf allen Systemen gleich bleibt die Unicode verwenden.

    > Frank schrieb: Zur Sicherheit - string's sind in .NET immer UTF-16. Du kannst sie nicht "falsch" codieren.

    Der String mit dem D. arbeitet (byteStringZumPosten, s. oben) ist falsch kodiert. In der Unicode-Codierung wird € nie als {128,0} kodiert! Ich habe bereits gesagt warum.

    > Wie gesagt, der PdfTextExtractor macht das wirklich 100% richtig.

    Die Aussage kenne ich ja schon. Du bist mir leider aber noch den Beweis schuldig geblieben. Mit Encoding.Default wird man nie einen Unicode-String verlustfrei dekodieren können. Oder sehe ich das falsch?

    > Die richtige Methode ist hier halt, den von mir genannten PdfTextExtractor zu benutzen

    [Schnipp] Ende der Diskussion.

    Gruss
    Marcel

    Mittwoch, 2. Februar 2011 16:29
    Moderator