Regulärer Ausdruck

  • Allgemein

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von BiedermannS.

    Regulärer Ausdruck

    Hallooo Leute..
    Ich bin nicht grade der hellste was Reguläre Ausdrücke angehen, von daher frage ich mal die Community.

    Habe folgenden code:

    Quellcode

    1. <!--
    2. <BASIC_INFO>
    3. KOREAN = DE_G36¹ÝÀú°Ý_D
    4. ENGLISH = DE_G36_D
    5. CODE = DE02
    6. ACTIVE = FALSE
    7. LABEL = 0
    8. </BASIC_INFO>
    9. <OPTION>
    10. ANIMATION = DE02
    11. </OPTION>
    12. <BUY_INFO>
    13. BUYABLE = FALSE
    14. BUYTYPE = 9
    15. BUYOPTION = 0
    16. COST = 0
    17. ADD_DINAR = 0
    18. REQ_BP = 67950
    19. REQ_LVL = 11
    20. RANDOM_NUM = 0
    21. </BUY_INFO>
    22. <USE_INFO>
    23. APPLY_TARGET = 0
    24. APPLY_OPTION = 0
    25. ADD_POING = 0
    26. DURATION_TIME = 0
    27. USEABLE_CHANNEL = 1,1,1,1
    28. </USE_INFO>
    29. <ABILITY_INFO>
    30. POWER = 400
    31. DEFENCE = 0
    32. SOOTRANGE = 5000
    33. AMMONNUM = 100
    34. MAGAZINENUM = 2
    35. EFFECTRANGE = 0
    36. PARABOLA = 1
    37. REACTAMOUNT = 1.850000
    38. REACTRECOVERY = 4.200000
    39. ACCURATE = 36.000000
    40. SHOOTSPEED = 11000
    41. WEIGHT = 20
    42. COOLTIME = 0.000000
    43. RELOADTIME = 750.000000
    44. HEATFACTOR = 0.000000
    45. COOLFACTOR = 0.000000
    46. FSDTIME = 0.000000
    47. SCDTIME = 0.000000
    48. ARMORTYPE = 0
    49. </ABILITY_INFO>
    50. <TARGET_INFO>
    51. PERSONAL = 100,100,100
    52. SURFACE = 2,0,0
    53. AIR = 2,0,0
    54. SHIP = 2,0,0
    55. </TARGET_INFO>
    56. //-->


    etwa 750 mal in einer Datei stehen.
    Es handelt sich offensichtlich um Waffen Informationen (für ein Spiel).
    Dazu möchte ich die Preise der Waffen und den Schaden sie anrichten in mein Programm laden.
    Im grunden genommen will ich CODE, BUYABLE, BUYTYPE, COST, ADD_DINAR, REQ_LVL, APPLY_TARGET, USEABLE_CHANNEL, POWER und AMMONUM.

    Mein bisheriger Ansatz:

    VB.NET-Quellcode

    1. Dim myCodeMatches As MatchCollection = Regex.Matches(itemsTxt, "CODE.+=.+(?<code>[a-zA-Z0-9]{4}?).+\n.+ACTIVE", RegexOptions.IgnoreCase + RegexOptions.Multiline)
    2. Dim myLabelMatches As MatchCollection = Regex.Matches(itemsTxt, "LABEL.+=.+(?<label>[0-9]+?).+\n.+\<", RegexOptions.IgnoreCase + RegexOptions.Multiline)
    3. Dim myDinarMatches As MatchCollection = Regex.Matches(itemsTxt, "COST.+=.+(?<dinar>[0-9\,\-]+?).+\n.+ADD_DINAR", RegexOptions.IgnoreCase + RegexOptions.Multiline)
    4. Dim myCreditsMatches As MatchCollection = Regex.Matches(itemsTxt, "ADD_DINAR.+=.+(?<credits>.+?).+\n.+REQ", RegexOptions.IgnoreCase + RegexOptions.Multiline)
    5. Dim myLevelMatches As MatchCollection = Regex.Matches(itemsTxt, "REQ_LVL.+=.+(?<level>[0-9]+?).+\n.+RANDOM", RegexOptions.IgnoreCase + RegexOptions.Multiline)
    6. Dim myBuyableMatches As MatchCollection = Regex.Matches(itemsTxt, "BUYABLE.+=.+(?<buyable>[a-zA-Z]{4,5}?).+\n.+BUY", RegexOptions.IgnoreCase + RegexOptions.Multiline)
    7. Dim myBuyoptionMatches As MatchCollection = Regex.Matches(itemsTxt, "BUYOPTION.+=.+(?<buyoption>[0-9]+?).+\n.+COST", RegexOptions.IgnoreCase + RegexOptions.Multiline)


    Wie gesagt, bin nicht der hellste.. :[
    Ich hoffe mir kann da jemand helfen bzw. das ganze besser lösen.
    Ansätze helfen mir auch :]
    Ist die Reihenfolge immer gleich? Sieht XML sehr ähnlich.

    Wenn sich die Struktur nicht ändert, könntest du das Ganze auch zeilenweise durchsuchen und entsprechend den Schlüsselwörtern eine Klasse/DataSet mit Daten befüllen.

    VB.NET-Quellcode

    1. Public Class Parser
    2. Inherits Dictionary(Of String, Weapon)
    3. Public Sub Parse(ByVal pfad As String)
    4. Using sr As New StreamReader(pfad, System.Text.Encoding.Default)
    5. Dim tmpline As String = String.Empty
    6. Dim current As New Weapon
    7. Do While Not sr.EndOfStream
    8. tmpline = sr.ReadLine
    9. If tmpline.Contains("</TARGET_INFO>") Then
    10. MyBase.Add(current.CODE, current)
    11. current = New Weapon
    12. ElseIf tmpline.Trim.StartsWith("CODE") Then
    13. current.CODE = tmpline.Split("="c)(1).Trim
    14. ElseIf tmpline.Trim.StartsWith("BUYABLE") Then
    15. current.BUYABLE = Boolean.Parse(tmpline.Split("="c)(1).Trim)
    16. ElseIf tmpline.Trim.StartsWith("Der Nächste Wert") Then
    17. 'Und so weiter
    18. End If
    19. Loop
    20. End Using
    21. End Sub
    22. Public Structure Weapon
    23. Public Property CODE As String
    24. Public Property BUYABLE As Boolean
    25. Public Property BUYTYPE As Integer
    26. Public Property COST As Integer
    27. Public Property ADD_DINAR As Integer
    28. Public Property REQ_LVL As Integer
    29. Public Property APPLY_TARGET As Integer
    30. Public Property USEABLE_CHANNEL As Integer()
    31. Public Property POWER As Integer
    32. Public Property AMMONUM As Integer
    33. End Structure
    34. End Class
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D
    So ich hab mal folgende Expression:

    Quellcode

    1. CODE\s+=\s+(?<code>[a-z0-9]{4}?).+BUYABLE\s+=\s+(?<buyable>(FALSE|TRUE)?).+BUYTYPE\s+=\s+(?<buytype>[0-9]?).+COST\s+=\s+(?<credits>.+?)\r\s+ADD_DINAR\s+=\s+(?<dinar>.+?)\r.+REQ_LVL\s+=\s+(?<level>[0-9]{1,3}?)\r.+APPLY_TARGET\s+=\s+(?<apply>[\-?[0-9]{1,2}]?).+USEABLE_CHANNEL\s+=\s+(?<channel>.+?)\r.+POWER\s+=\s+(?<power>[0-9]{1,5}).+AMMONNUM\s+=\s+(?<ammo>[0-9]{1,6}?)\r


    Funktioniert super bei RegExr ( Programm ).
    Hab die Flags ism ( ignore case, dotall, multiline ).

    Mein Code:

    Quellcode

    1. BinFile.BinReader mReader = new BinFile.BinReader();
    2. string mItems = mReader.DecryptBinFile("data/items.bin");
    3. string mPattern = "CODE\\s+=\\s+(?<code>[a-z0-9]{4}?).+BUYABLE\\s+=\\s+(?<buyable>(FALSE|TRUE)?).+BUYTYPE\\s+=\\s+(?<buytype>[0-9]?).+COST\\s+=\\s+(?<credits>.+?)\\r\\s+ADD_DINAR\\s+=\\s+(?<dinar>.+?)\\r.+REQ_LVL\\s+=\\s+(?<level>[0-9]{1,3}?)\\r.+APPLY_TARGET\\s+=\\s+(?<apply>[\\-?[0-9]{1,2}]?).+USEABLE_CHANNEL\\s+=\\s+(?<channel>.+?)\\r.+POWER\\s+=\\s+(?<power>[0-9]{1,5}).+AMMONNUM\\s+=\\s+(?<ammo>[0-9]{1,6}?)\\r";
    4. System.Text.RegularExpressions.MatchCollection mCollection = System.Text.RegularExpressions.Regex.Matches(mItems, mPattern, System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);
    5. foreach (System.Text.RegularExpressions.Match mMatch in mCollection)
    6. {
    7. Console.WriteLine("Found Item: " + mMatch.Groups["code"].Value);
    8. }


    Trotzdem habe ich 0 ergebnisse... Jemand ne idee warum? : [
    Falls ' oder \ im Text drin vorkommen mag VB.net die nicht richtig erkennen. Zumindest hatte ich immer diese Problem bis ich das mal ausprobiert hatte. ;)
    Ich glaub man muss für ein \ drei schreiben also so: \\\
    Bin mir aber nicht sicher, müsste man ausprobieren. Ein Azubikollege hatte in der Ausbildung mal langeweile und hat für sowas mal ein Tool geschrieben gehabt :P das hatten wir dann immer benutzt deswegen meine Unsicherheit ;)
    Und mit RegEx zu arbeiten, wo es nicht benötigt wird zeugt natürlich von Intelligenz.
    Selbst wenn du einen Regex hast, welcher alles findet, hast du dennoch keine Zuordnung zu den einzelnen Objekten.

    Anstatt die Struktur die gegeben ist zu analysieren und einen anständigen Parser dafür zu schreiben, nehmen wir doch einfach RegEx, selbst wenn es nicht das gewünschte Ergebnis bringen wird. :huh:

    Das war keine Alternative, sondern ein Wink mit dem Zaunpfahl. RegEx ist zum suchen von Pattern bzw. zum Prüfen von Eingaben, nicht zum Filtern von Ganzen Texten auf zig Daten und diese dann auch noch zuordnen.


    Aber mir egal, wenn du die Hilfe nicht willst, dann mach es weiter mit RegEx, aber damit machst du dir nur mehr Kopfschmerzen als notwendig...
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D
    Naja muss mich entschuldigen.
    Habs ohne RegEx jetzt doch anders gelöst. :D

    C-Quellcode

    1. private static List<ShopItem> _Items;
    2. public static void LoadItems()
    3. {
    4. Shop._Items = new List<ShopItem>();
    5. BinFile.BinReader mReader = new BinFile.BinReader();
    6. string mItems = mReader.DecryptBinFile("data/items.bin");
    7. Dictionary<string, string> mTemp = new Dictionary<string, string>();
    8. foreach (string mLine in mItems.Split('\n'))
    9. {
    10. if(mLine.Contains("="))
    11. {
    12. string mKey = mLine.Split('=')[0].Trim();
    13. string mValue = mLine.Split('=')[1].Trim();
    14. if (mTemp.ContainsKey(mKey))
    15. {
    16. if (mTemp.ContainsKey("BUYABLE") && mTemp.ContainsKey("CODE") && mTemp.ContainsKey("COST") && mTemp.ContainsKey("ADD_DINAR") && mTemp["BUYABLE"] == "TRUE")
    17. Shop._Items.Add(ShopItem.Unpack(mTemp["CODE"], mTemp["COST"], mTemp["ADD_DINAR"]));
    18. mTemp.Clear();
    19. }
    20. else
    21. mTemp.Add(mKey, mValue);
    22. }
    23. }
    24. Engine.Logging.Notification("Loaded Items [ " + Shop._Items.Count.ToString() + " total ]");
    25. }


    Naja wurst :D
    Ich hab hier noch was:

    VB.NET-Quellcode

    1. Public Class Parser
    2. Inherits Dictionary(Of String, Weapon)
    3. Public Sub ParseText(ByVal Text As String)
    4. Dim lines As String() = Text.Split(vbCrLf.ToCharArray)
    5. Dim tmpline As String = String.Empty
    6. Dim current As New Weapon
    7. Dim prop As String() = Nothing
    8. For Each tmpline In lines
    9. If tmpline.Contains("</TARGET_INFO>") Then
    10. MyBase.Add(current.CODE, current)
    11. current = New Weapon
    12. Else
    13. prop = tmpline.Split("="c)
    14. If prop.Count = 2 Then
    15. current.SetValueByName(prop(0).Trim, prop(1).Trim)
    16. End If
    17. End If
    18. Next
    19. End Sub
    20. Public Sub ParseFile(ByVal pfad As String)
    21. Using sr As New StreamReader(pfad, System.Text.Encoding.Default)
    22. Dim tmpline As String = String.Empty
    23. Dim current As New Weapon
    24. Dim prop As String() = Nothing
    25. Do While Not sr.EndOfStream
    26. tmpline = sr.ReadLine
    27. If tmpline.Contains("</TARGET_INFO>") Then
    28. MyBase.Add(current.CODE, current)
    29. current = New Weapon
    30. Else
    31. prop = tmpline.Split("="c)
    32. If prop.Count = 2 Then
    33. current.SetValueByName(prop(0).Trim, prop(1).Trim)
    34. End If
    35. End If
    36. Loop
    37. End Using
    38. End Sub
    39. Public Class Weapon
    40. Public Property CODE As String
    41. Public Property BUYABLE As Boolean
    42. Public Property BUYTYPE As Integer
    43. Public Property COST As Integer
    44. Public Property ADD_DINAR As Integer
    45. Public Property REQ_LVL As Integer
    46. Public Property APPLY_TARGET As Integer
    47. Public Property USEABLE_CHANNEL As Integer()
    48. Public Property POWER As Integer
    49. Public Property AMMONUM As Integer
    50. Sub New()
    51. CODE = String.Empty
    52. BUYABLE = False
    53. BUYTYPE = -1
    54. COST = -1
    55. ADD_DINAR = -1
    56. REQ_LVL = -1
    57. APPLY_TARGET = -1
    58. USEABLE_CHANNEL = {-1}
    59. POWER = -1
    60. AMMONUM = -1
    61. End Sub
    62. Default Public ReadOnly Property GetValueByName(ByVal Name As String) As Object
    63. Get
    64. Dim pi As Reflection.PropertyInfo = Me.GetType.GetProperty(Name)
    65. If Not pi Is Nothing AndAlso Not Name.ToLower.Contains("getvaluebyname") Then
    66. Return pi.GetValue(Me, Nothing)
    67. Else
    68. Throw New ArgumentException("Class does not contain Property (" & Chr(34) & Name & Chr(34) & ")!", "Name")
    69. Return Nothing
    70. End If
    71. End Get
    72. End Property
    73. Public Overrides Function ToString() As String
    74. Dim sb As New System.Text.StringBuilder
    75. For Each m As Reflection.PropertyInfo In Me.GetType.GetProperties
    76. If m.PropertyType = GetType(Integer()) Then
    77. Dim s As String = String.Empty
    78. For Each el As Integer In DirectCast(Me(m.Name), Integer())
    79. s &= el.ToString & ","
    80. Next
    81. sb.Append(String.Format("{0}: ({1}){2}", m.Name, s.Substring(0, s.Length - 1), vbTab))
    82. ElseIf Not m.Name.Contains("GetValueByName") Then
    83. sb.Append(String.Format("{0}: {1}{2}", m.Name, Me(m.Name).ToString, vbTab))
    84. End If
    85. Next
    86. Return sb.ToString
    87. End Function
    88. Sub SetValueByName(ByVal Name As String, ByVal Value As String, Optional ByVal ArraySplitChar As Char = ","c)
    89. Dim pi As Reflection.PropertyInfo = Me.GetType.GetProperty(Name)
    90. If Not pi Is Nothing Then
    91. If pi.PropertyType.IsAssignableFrom(GetType(Integer())) Then
    92. Dim arr As Integer() = Array.ConvertAll(Of String, Integer)(Value.Split(ArraySplitChar), Function(s As String) As Integer
    93. Return Integer.Parse(s)
    94. End Function)
    95. pi.SetValue(Me, arr, Nothing)
    96. Else
    97. If pi.PropertyType.IsAssignableFrom(GetType(Double)) Then
    98. pi.SetValue(Me, Double.Parse(Value, Globalization.NumberStyles.AllowDecimalPoint, New Globalization.NumberFormatInfo() With {.CurrencyDecimalSeparator = "."}), Nothing)
    99. ElseIf pi.PropertyType.IsAssignableFrom(GetType(Integer)) Then
    100. pi.SetValue(Me, Integer.Parse(Value), Nothing)
    101. ElseIf pi.PropertyType.IsAssignableFrom(GetType(Boolean)) Then
    102. pi.SetValue(Me, Boolean.Parse(Value), Nothing)
    103. Else
    104. pi.SetValue(Me, Value, Nothing)
    105. End If
    106. End If
    107. End If
    108. End Sub
    109. End Class
    110. End Class


    Aufruf erfolgt so:

    VB.NET-Quellcode

    1. Dim p As New Parser
    2. 'p.ParseText(s) ' Parsen eines Textes
    3. p.ParseFile("c:\pfad.txt") 'Parsen einer Datei
    4. 'Hier werden die gesammelten Daten des Parsers Formatiert und im Debug
    5. For Each kv As KeyValuePair(Of String, Parser.Weapon) In p
    6. 'ToString gibt alles als Text aus
    7. MsgBox(kv.Value.ToString)
    8. 'Normaler Aufruf über die Eigenschaft
    9. MsgBox(kv.Value.POWER.ToString)
    10. 'Aufruf über den Namen, wirft eine Exception wenn der Name der Eigenschaft nicht vorhanden ist
    11. MsgBox(kv.Value("POWER").ToString)
    12. next


    Der Vorteil hier ist, dass du diese Methode leicht erweitern kannst. Du brauchst nur in der Klasse eine neue Eigenschaft hinzufügen, durch die Reflection werden alle vorhandenen Properties gesetzt.

    Wenn du z.B.: die Reloadtime auch mitnehmen willst, fügst du der Klasse Weapon einfach die Eigenschaft RELOADTIME hinzu:

    VB.NET-Quellcode

    1. Public Property RELOADTIME as Double


    Mfg
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

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