Zeichenkette aus String extrahieren

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Zeichenkette aus String extrahieren

    So, guten Abend allerseits,

    ich bin gerade dabei, die Ausgabe einer CDDB-Datenbank (da kann man von CDs die Titelinfos bekommen) auszuwerten.

    Der String, den mir die DB liefert, sieht so aus:

    Spoiler anzeigen
    210 data 8909930b CD database entry follows (until terminating `.')
    # xmcd
    #
    # Track frame offsets:
    # 150
    # 17687
    # 37555
    # 54855
    # 69407
    # 89350
    # 107235
    # 121315
    # 140962
    # 155695
    # 166937
    #
    # Disc length: 2453 seconds
    #
    # Revision: 0
    # Processed by: cddbd v1.5.2PL0 Copyright (c) Steve Scherf et al.
    # Submitted via: gnudb v1.0.1
    #
    DISCID=8909930b
    DTITLE=3 Doors Down / The Better Life ##############Um diese Zeile geht es!!!
    DYEAR=2000
    DGENRE=acoustic rock
    TTITLE0=Kryptonite
    TTITLE1=Loser
    TTITLE2=Duck and Run
    TTITLE3=Not Enough
    TTITLE4=Be Like That
    TTITLE5=Life of My Own
    TTITLE6=The Better Life
    TTITLE7=Down Poison
    TTITLE8=By My Side
    TTITLE9=Smack
    TTITLE10=So I Need You
    EXTD=
    EXTT0=
    EXTT1=
    EXTT2=
    EXTT3=
    EXTT4=
    EXTT5=
    EXTT6=
    EXTT7=
    EXTT8=
    EXTT9=
    EXTT10=
    PLAYORDER=
    .


    Jetzt möchte ich bestimmte Infos extrahieren, z.B. Interpret, Album, Musiktitel, etc.. Soweit so gut. Bisher habe ich also Folgendes:

    VB.NET-Quellcode

    1. Public Function ExtrahiereInterpretUndAlbum(Daten As String) As String 'Der String der vom CDDB Server kommt wird hier als Argument übergeben
    2. Dim cddbStartposition As Integer = Daten.IndexOf("DTITLE=") + 7 'hier wird die Startposition ermittelt
    3. Dim cddbEndposition As Integer = cddbStartposition + Daten.IndexOf(Environment.NewLine, cddbStartposition) - 1 'hier wird die Endposition ermittelt
    4. Dim InterpretUndAlbum As String = Daten.Substring(cddbStartposition, cddbEndposition - cddbStartposition) 'hier wird der String extrahiert
    5. Return InterpretUndAlbum
    6. End Function


    Ich möchte die Zeile mit dem Interpret und dem Albumnamen "3 Doors Down / The Better Life" komplett extrahieren (Zeile 24 im Spoiler, da wo steht: Um diese Zeile geht es!!!!)

    Hier bekomme ich in Zeile 4 den Fehler:
    System.ArgumentOutOfRangeException
    HResult=0x80131502
    Nachricht = Der Index und die Länge müssen sich auf eine Position in der Zeichenfolge beziehen.
    Parametername: length

    Soweit verstanden.

    Ich denke der Fehler ist in Zeile 3. Da will ich die Endposition ermitteln, indem ich zur Startposition das erste Vorkommen eines Zeilenumbruchs ermittele und 1 abziehe. Das ist wohl so nicht korrekt...

    Wenn ich einen Haltepunkt setze, ist cddbStartposition = 425 und cddbEndposition = 879. Also weit gefehlt.

    Wie also ermittle ich sonst den Index des Zeilenumruchs (ich denke das ist das Problem)?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Der Punkt ist, dass das ein großer String ist. Wenn Du ihn zeilenweise hättest, würde reichen:

    VB.NET-Quellcode

    1. Dim InterpretUndAlbum As String = Daten.Substring(cddbStartposition)

    Es wird dann automatisch der Rest der Zeile hergenommen. Naja, und wie Du aus einem String mit Umbrüchen ein String-Array ohne Umbrüche machst, weißt Du ja bestimmt …

    Allerdings ist dieses Dim cddbStartposition As Integer = Datenzeile.IndexOf("DTITLE=") + 7 etwas komisch auf den ersten Blick. Schreib lieber zur Klar- und Sicherheit:
    Dim cddbStartposition As Integer = Daten.IndexOf("DTITLE=") + "DTITLE=".Length

    Ein ähnliches Problem habe ich grad an der Backe, bei dem ich Daten aus verschiedenen PDFs auslese, die alle (leider nur grundsätzlich) den gleichen Aufbau haben.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Es wird dann automatisch der Rest der Zeile hergenommen. Naja, und wie Du aus einem String mit Umbrüchen ein String-Array ohne Umbrüche machst, weißt Du ja bestimmt …


    Ne bis dato noch net... Aber hab folgendes gefunden:

    Dim cddbErgebnis As List(Of String) = Daten.Split(New Char() {Environment.NewLine}).ToList

    Damit sollte es gehen :) Danke für den Denkanstoss
    Ich hab das mit C#, HttpClient und Regex gemacht (klick Bildanhang).

    0. Hol die Daten die unter gnudb.org/gnudb/rock/820bdd0a 'liegen' (ACDC irgendwas Canada)
    1. 'gesamt-String'.Split bei jedem NewLineCharacter
    2. gehe durch jede Zeile
    3.falls gleich "DTITLE=" dann nimm alles nach dem '='
    4. das selbe für "TTITLEXXX" wobei X=jede beliebige Nummer sein kann

    Du kannst den Code ja schnell so verändern das er alles matches was Du raus haben möchtest.

    Spoiler anzeigen

    C#-Quellcode

    1. using System.Text.RegularExpressions;
    2. namespace WF_CdDb_HttpClient
    3. {
    4. public partial class Form1 : Form
    5. {
    6. public Form1()
    7. {
    8. InitializeComponent();
    9. TxbxUrl.Text = "https://gnudb.org/gnudb/rock/820bdd0a";
    10. }//ACDC irgendwas -> https://gnudb.org/gnudb/rock/820bdd0a
    11. private async void BtnGetUrlData_Click(object sender, EventArgs e)
    12. {
    13. using var client = new HttpClient();
    14. var content = await client.GetStringAsync(TxbxUrl.Text);
    15. //show the 'raw' webpage-data
    16. RtxbxShowData.Text = content;
    17. //split string at every newLine-character
    18. string[] lines = content.Split(
    19. new string[] { "\r\n", "\r", "\n" },
    20. StringSplitOptions.None
    21. );
    22. foreach (string line in lines)
    23. {
    24. //if somewhere in the line this 'DTITLE=' matches ...
    25. if (Regex.IsMatch(line, @"DTITLE="))
    26. {//Title -- get everthing after the '=' in that line
    27. var title = Regex.Match(line, @"=(.*)$").Groups[1].Value;
    28. RtxbxShowResult.Text += title + $"\n";
    29. }
    30. //if somewhere in the line this 'TTitleXXXXX=' matches, where X=any number then ...
    31. if (Regex.IsMatch(line, @"TTITLE\d+="))
    32. {//TrackTitle -- get everthing after the '=' in that line
    33. var song = Regex.Match(line, @"=(.*)$").Groups[1].Value;
    34. RtxbxShowResult.Text += song + $"\n";
    35. }
    36. }
    37. }
    38. }
    39. }


    ohne Gewähr mit Telerik C# -> VB.Net

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Text.RegularExpressions
    2. Namespace WF_CdDb_HttpClient
    3. Public Partial Class Form1
    4. Inherits Form
    5. Public Sub New()
    6. InitializeComponent()
    7. TxbxUrl.Text = "https://gnudb.org/gnudb/rock/820bdd0a"
    8. End Sub
    9. Private Async Sub BtnGetUrlData_Click(ByVal sender As Object, ByVal e As EventArgs)
    10. Using client = New HttpClient()
    11. End Using
    12. Dim content = Await client.GetStringAsync(TxbxUrl.Text)
    13. RtxbxShowData.Text = content
    14. Dim lines As String() = content.Split(New String() {vbCrLf, vbCr, vbLf}, StringSplitOptions.None)
    15. For Each line As String In lines
    16. If Regex.IsMatch(line, "DTITLE=") Then
    17. Dim title = Regex.Match(line, "=(.*)$").Groups(1).Value
    18. RtxbxShowResult.Text += title & $"\n"
    19. End If
    20. If Regex.IsMatch(line, "TTITLE\d+=") Then
    21. Dim song = Regex.Match(line, "=(.*)$").Groups(1).Value
    22. RtxbxShowResult.Text += song & $"\n"
    23. End If
    24. Next
    25. End Sub
    26. End Class
    27. End Namespace


    Lg nogood



    und noch mal mit ein bisschen kürzer mit Linq:

    Spoiler anzeigen

    C#-Quellcode

    1. using System.Text.RegularExpressions;
    2. namespace WF_CdDb_HttpClient
    3. {
    4. public partial class Form1 : Form
    5. {
    6. public Form1()
    7. {
    8. InitializeComponent();
    9. TxbxUrl.Text = "https://gnudb.org/gnudb/rock/820bdd0a";
    10. }//ACDC irgendwas -> https://gnudb.org/gnudb/rock/820bdd0a
    11. private async void BtnGetUrlData_Click(object sender, EventArgs e)
    12. {
    13. using var client = new HttpClient();
    14. var content = await client.GetStringAsync(TxbxUrl.Text);
    15. RtxbxShowData.Text = content;
    16. string[] lines = content.Split(new [] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
    17. var linqTitle = lines.Where(line => Regex.IsMatch(line, @"DTITLE=")).FirstOrDefault();
    18. var linqTrackTitle = lines.Where(line => Regex.IsMatch(line, @"TTITLE\d+="));
    19. if (linqTitle != null)
    20. RtxbxShowResult.Text += $"{Regex.Match(linqTitle, @"=(.*)$").Groups[1].Value}\n";
    21. foreach (var item in linqTrackTitle)
    22. RtxbxShowResult.Text += $"{Regex.Match(item, @"=(.*)$").Groups[1].Value}\n";
    23. }
    24. }
    25. }​
    Bilder
    • VB_CDDB.jpg

      118,59 kB, 795×670, 32 mal angesehen
    codewars.com Rank: 4 kyu

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nogood“ ()

    VB.NET-Quellcode

    1. Daten.Split(New Char() {Environment.NewLine}).ToList
    :?: Das ist aber Option Strict Off :!:

    so wär's besser:

    VB.NET-Quellcode

    1. Daten.Split({Environment.NewLine}, StringSplitOptions.None)

    Da wird dann die Überladung verwendet, die einen String als Splitter/Delimiter akzeptiert.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed

    Ja ich war noch im Option Strict Off-Modus, weil ich noch nicht mal wusste, ob gnudb.gnudb.org, also die CDDB noch online ist.....

    Schon umgestellt :) ... Bei deiner Codezeile gehen dann auch automatisch die Zeilenumbrüche mit raus, sonst hätt ich die nochmals mit .Substring rausholen müssen...

    Also danke :)

    Edit: Hab mir jetzt eine Klasse geschrieben, welche alle relevanten Infos aus dem String vom CDDB SERVER extrahiert. Hat auf Anhieb funktioniert... So solls sein :)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()