.h Datei öffnen, in Array lade, alle Zeilen zählen, sortieren...

  • Hallo zusammen,
    die Suchfunktion konnte mir schon weiterhelfen, bräuchte aber spezifischere Informationen.

    Folgendes soll geschehen:
    1. Öffnen einer test.h-Datei UND einer test.c-Datei (beide können als .txt-Datei geöffnet und gelesen werden)
    2. Jede Zeile, die nicht mit #define beginnt soll gelöscht werden
    3. Alle #define sollen gelöscht werden
    4. Nach Parameter sortieren (dazu aber erst später)

    Das habe ich bis jetzt:
    1. Eine Oberfläche mit "Datei>öffnen", Hilfe und beenden und OK-Button
    2. mit _FileReadToArray kann ich die test.h einlesen, die Zeilen mit Array[0] auslesen und auf jede Zeile zugreifen
    3. Ausgabe der einzelnen Zeilen über Msgbox

    Das würde ich gerne wissen:
    1. In _FileReadToArray muss ich den festen Dateinahmen eingeben, ich würde die Datei jedoch gerne mit dem FileOpenDialog bzw, FileOpen öffnen, da die Dateinamen unterschiedlich sind.

    2. Wenn eine neue Zeile nicht mit #define beginnt, gleich löschen. Wie kann ich alle nachfolgenden Zeilen um ein gelöschtes Array nach oben verschieben?

    3. Gibt es eine Maske, die nach bestimmten Parametern in einer Zeile sucht, z.B Adressen die so aussehen könnten 8, 10, 12, 14, 15, 16, 18, 19, 20... (also um 1 oder 2 erhöht werden)

    Ich habe noch einige Fragen, aber die würde ich gerne erst stellen, wenn ich den Einstieg gefunden habe.
    Hat jemand vielleicht sogar schon etwas ähnliches gemacht? .txt-Datei mit relativen Phad öffnen, nach bestimmten Parametern durchsuchen, sortieren und als neue .txt-Datei speichern.

    Wäre auch über andere Verfahren oder Beispiele sehr erfreut.

    P.S. bei meinem ersten Beitrag trat wohl ein Fehler auf, deshalb gleicher Beitrag nochmal.


    Vielen Dank
    Michael

    Einmal editiert, zuletzt von Michael_Scott (31. August 2010 um 07:32) aus folgendem Grund: Wurde in Rekordzeit beantwortet. Super Forum Grüße an alle Michael

  • Ich hab da mal ein kl. Beispiel erstellt das hoffentlich einigermaßen das tut was du willst^^

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #include <File.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $file = FileOpenDialog("Wähle die Datei", @ScriptDir, "All (*.*)"); Datei öffnen Dialog
    Local $aRead
    _FileReadToArray($file, $aRead); datei in Array einlesen
    For $i = $aRead[0] To 1 Step -1 ; Rückwärts zählen ist wichtig sonst bekommst du nen error
    If StringLeft($aRead[$i], 7) <> "#define" Then ; wenn die Zeile mit nicht mit #define beginnt
    _ArrayDelete($aRead, $i); dann lösche sie
    EndIf
    If StringInStr($aRead[$i], "#define") Then; wenn die zeile #define enthält
    $aRead[$i] = StringReplace($aRead[$i], "#define", ""); dann lösche #define herraus
    EndIf
    Next
    _ArrayDelete($aRead, 0); lösche index 0 indem die Zeilenanzahl steht

    [/autoit] [autoit][/autoit] [autoit]

    _FileWriteFromArray(@ScriptDir & "\new.txt", $aRead); schreibe eine neue Datei

    [/autoit]


    Deine 3te Frage sieht mir nach StringRegExp() aus, bin mir da aber nicht sicher was genau du willst

    Gruß
    Schnitzel

  • Klasse, danke,
    dein Code bringt bei mir zwar die Fehlermeldung:
    Array variable has incorrect number of subscripts or subscript dimension range exceeded.
    If StringInStr($aRead[$i], "#define") Then
    If StringInStr(^ Error

    aber trotzdem kann ich aus deinem Beispiel sehr viel benutzen, danke.

    Der nächste Schritt wäre nun eine zweite Datei zu öffnen, formatieren wie schon bei der ersten (das schaff ich nun). In der ersten formatierten .txt-Datei steht nun am Anfang immer ein Bezeichnung z.B. Rampe1, in der zweiten Datei steht ein bestimmter Wert z.B. "Rampe1; 20"
    Nun möchte ich den Wert auslesen und in die erste Datei am Ende der jeweilgen Zeile anhängen.
    Am Ende soll dann eine .txt-Datei (besser noch eine CSV-Datei) erzeugt werden, die in etwa so aussehen soll:

    Code
    Adresse     Bezeichnung	  Faktor     Einheit     Wert
    8          	Rampe1        	0,1    	mA     	20
    10        	Rampe2        	1,0    	mA     	2
    ...


    Super Forum, Vielen Dank
    Michael

    • Offizieller Beitrag

    Willkommen hier im Forum!

    Kannst Du mal so eine Datei posten?
    Falls da persönliche/vertrauliche Daten drinstehen, dann eine entsprechend angepasste Datei.
    Und dann dazuschreiben, was Du von den Daten brauchst.
    Meist ist der Einsatz von StringRegExp viel effektiver, statt alles in ein Array einzulesen und daraus dann wieder zu löschen.

  • Ok, hier ist ein Ausschnitt der .h-Datei, das Problem ist, dass Leerzeichen und TAB darin nicht einheitlich vorkommen.

    Spoiler anzeigen
    Code
    #define PWM1_MIN  8,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/
    #define PWM1_MAX  10,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/
    #define RAMPE_P1    12,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/
    #define RAMPE_P2 14,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/
    #define PWM2_MIN  16,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/
    #define PWM2_MAX  18,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/

    hiervon brauche ich ein Konstrukt, dass so aufgebaut ist.
    Adresse, Bezeichnung, Faktor, Einheit

    Code
    8;PWM1_MIN;1;mA
    10;PWM1_MAX;1;mA
    12;RAMPE_P1;0,1;s
    ...

    Diese .txt wir nun abgespeichert und anschließend die .c-Datei geöffnet. Diese ist folgendermaßen aufgebaut

    Spoiler anzeigen
    Code
    s32_error |= ba_llt_writeTempEEPROM(PWM1_MIN, 200);
    s32_error |= ba_llt_writeTempEEPROM(PWM1_MAX, 800);
    s32_error |= ba_llt_writeTempEEPROM(PWM2_MIN, 200);
    s32_error |= ba_llt_writeTempEEPROM(PWM2_MAX, 800);
    s32_error |= ba_llt_writeTempEEPROM(PWM3_MIN, 200);
    s32_error |= ba_llt_writeTempEEPROM(PWM3_MAX, 800);

    Nun muss zu jeder Bezeichnung der Wert verknüpft werden (PWM1_MIN; 200)

    Als letzten Schritt wieder die erste Datei öffnen und den Wert hinten anhängen, so das letztendlich für jede Zeile dieses Konstrukt entsteht:
    8;PWM1_MIN;1;mA; 200
    u.s.w
    (etwa 1500 Zeilen)

    Ich weiß nicht ob es nicht einen leichteren Ansatz als meinen gibt, bin für jede Hilfe dankbar.

    Viele Grüße
    Michael

  • Dieses StringRegExp scheint sehr mächtig zu sein und ist scheinbar genau auf mein Problem zugeschnitten, leider kann ich mit der Hilfe und dem Beispiel nicht so viel anfangen. Kennt sich jemand mit diesen Regular Expression gut aus und kann mir helfen, oder kennt jemand ein gutes Beispiel in dem besser ersichtlich ist, wie regular expressions angewendet werden?

    Vielen Dank
    Michael

  • Hallo, mal als Einstieg:

    [autoit]

    ; $Header = FileRead("Dingens.h")
    ; $Code = FileRead("Dingens.c")
    $Header = "#define PWM1_MIN 8,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/" & @CRLF & _
    "#define PWM1_MAX 10,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/" & @CRLF & _
    "#define RAMPE_P1 12,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/" & @CRLF & _
    "#define RAMPE_P2 14,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/" & @CRLF & _
    "#define PWM2_MIN 16,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/" & @CRLF & _
    "#define PWM2_MAX 18,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/"
    $Code = "s32_error |= ba_llt_writeTempEEPROM(PWM1_MIN, 200);" & @CRLF & _
    "s32_error |= ba_llt_writeTempEEPROM(PWM1_MAX, 800);" & @CRLF & _
    "s32_error |= ba_llt_writeTempEEPROM(PWM2_MIN, 200);" & @CRLF & _
    "s32_error |= ba_llt_writeTempEEPROM(PWM2_MAX, 800);" & @CRLF & _
    "s32_error |= ba_llt_writeTempEEPROM(PWM3_MIN, 200);" & @CRLF & _
    "s32_error |= ba_llt_writeTempEEPROM(PWM3_MAX, 800);"
    $Pattern1 = "(?i)(?m)^#define\s*(\w+)\s*(\d+),\w+/\*([\d.]+),(\w+).*$"
    $Replace1 = "$2;$1;$3;$4"
    MsgBox(0, "RegEx1", StringRegExpReplace($Header, $Pattern1, $Replace1))
    $Pattern2 = "(?i)(?m)^[^(]+\((\w+),\s*(\d+).*$"
    $Replace2 = "$1;$2"
    MsgBox(0, "RegEx2", StringRegExpReplace($Code, $Pattern2, $Replace2))
    Exit

    [/autoit]
    • Offizieller Beitrag

    Und hier komplett:

    Spoiler anzeigen
    [autoit]


    $sData_h = FileRead(@ScriptDir & '\test.h')
    $aOut_h = StringRegExp($sData_h, '#define\s+(\S+?)\s+(\d+),.+/\*(.+),(.+),.+/', 3)
    $sData_c = FileRead(@ScriptDir & '\test.c')
    $aOut_c = StringRegExp($sData_c, '.+\((.+?, \d+)\);', 3)
    If IsArray($aOut_h) Then
    $hFile = FileOpen(@ScriptDir & '\test_out.h', 2)
    If $hFile <> -1 Then
    For $i = 0 To UBound($aOut_h) - 1 Step 4
    $sTmp = ''
    For $j = 0 To UBound($aOut_c) - 1
    If StringInStr($aOut_c[$j], $aOut_h[$i]) Then
    $sTmp = ';' & StringMid($aOut_c[$j], StringInStr($aOut_c[$j], ', ') + 2)
    ExitLoop
    EndIf
    Next
    FileWriteLine($hFile, $aOut_h[$i + 1] & ';' & $aOut_h[$i] & ';' & $aOut_h[$i + 2] & ';' & $aOut_h[$i + 3] & $sTmp)
    Next
    FileClose($hFile)
    EndIf
    EndIf

    [/autoit]
  • Vielen vielen Dank an alle, besonders an Oscar.
    Ich werde noch ein bischen Zeit benötigen um das ganze nachzuvollziehen, aber mit den test.h und test.c funktioniert das schon wunderbar. Nun muss ich das noch in meinen Quelltext einbinden und ein bischen modifizieren. Vielleicht hab ich dann noch ein, zwei Fragen.


    Ich bin als Neuling in diesem Forum total von der Unterstützung begeister, so etwas habe ich in anderen Foren noch nie erlebt. Macht weiter so, echt spitze hier. :thumbup:

    Viele Grüße
    Michael

  • Sehr gut, klappt bei 98% der über 1500 Zeilen, spitze.
    Leider bin ich mit der Syntax noch überfordert. Ich habe mir statt der test_out.h eine test_out.csv erstellen lassen und mit excel geöffnet, sieht sehr gut aus. Noch eine Kleinigkeit, in der ersten Zeile der .txt bzw. .csv soll stehen:
    Adresse; Bezeichnung; Faktor; Einheit; akt. Wert; Wert1; Wert2; Wert3 (wenn möglich Fett und Schriftgröße 14 als .csv-Datei)

    Das Grundgerüst ist dank Oscar's hilfe fertig, für den Feinschliff sollte die Suchfunktion hier ausreichend sein.


    Viele Grüße
    Michael

    • Offizieller Beitrag

    Dann sind die anderen 2% irgendwie anders formatiert. Vielleicht kannst Du die mal posten?

    Für die zusätzliche Zeile einfach beim erstellen der Datei einfügen lassen:

    Spoiler anzeigen
    [autoit]


    $sData_h = FileRead(@ScriptDir & '\test.h')
    $aOut_h = StringRegExp($sData_h, '#define\s+(\S+?)\s+(\d+),.+/\*(.+),(.+),.+/', 3)
    $sData_c = FileRead(@ScriptDir & '\test.c')
    $aOut_c = StringRegExp($sData_c, '.+\((.+?, \d+)\);', 3)
    If IsArray($aOut_h) Then
    $hFile = FileOpen(@ScriptDir & '\test_out.csv', 2)
    If $hFile <> -1 Then
    FileWriteLine($hFile, 'Adresse; Bezeichnung; Faktor; Einheit; akt. Wert; Wert1; Wert2; Wert3')
    For $i = 0 To UBound($aOut_h) - 1 Step 4
    $sTmp = ''
    For $j = 0 To UBound($aOut_c) - 1
    If StringInStr($aOut_c[$j], $aOut_h[$i]) Then
    $sTmp = ';' & StringMid($aOut_c[$j], StringInStr($aOut_c[$j], ', ') + 2)
    ExitLoop
    EndIf
    Next
    FileWriteLine($hFile, $aOut_h[$i + 1] & ';' & $aOut_h[$i] & ';' & $aOut_h[$i + 2] & ';' & $aOut_h[$i + 3] & $sTmp)
    Next
    FileClose($hFile)
    EndIf
    EndIf

    [/autoit]
  • Ja, bei den 2% handelt es sich um Kommentare, das ganze sieht dann so aus:

    Code
    #define 	PWM1_MIN  		8,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/
    #define 	PWM1_MAX  		10,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/
    #define RAMPE_P1_AUF   		12,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/
    //#define RAMPE_P1_AB 		14,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/
    #define 	PWM2_MIN  		16,B_EEPROM_2BYTE_U/*1,mA,#PWM#ESX#STROM*/

    Also als Pseudocode:
    Wenn eine Zeile mit // beginnt, ignorieren und weiter zur nächsten Zeile.

    Is bestimmt kein Aufwand, muss bzw. will dein Skript erst mal der Reihe nach durchgehen. Vielleicht hast du ja gleich ne Lösung parat.

    Vielen Dank
    Michael

    • Offizieller Beitrag

    Kleine Änderung am RegExp-Pattern:

    Spoiler anzeigen
    [autoit]


    $sData_h = FileRead(@ScriptDir & '\test.h')
    $aOut_h = StringRegExp($sData_h, '(?:[^//]|\A)#define\s+(\S+?)\s+(\d+),.+/\*(.+),(.+),.+/', 3)
    $sData_c = FileRead(@ScriptDir & '\test.c')
    $aOut_c = StringRegExp($sData_c, '.+\((.+?, \d+)\);', 3)
    If IsArray($aOut_h) Then
    $hFile = FileOpen(@ScriptDir & '\test_out.csv', 2)
    If $hFile <> -1 Then
    FileWriteLine($hFile, 'Adresse; Bezeichnung; Faktor; Einheit; akt. Wert; Wert1; Wert2; Wert3')
    For $i = 0 To UBound($aOut_h) - 1 Step 4
    $sTmp = ''
    For $j = 0 To UBound($aOut_c) - 1
    If StringInStr($aOut_c[$j], $aOut_h[$i]) Then
    $sTmp = ';' & StringMid($aOut_c[$j], StringInStr($aOut_c[$j], ', ') + 2)
    ExitLoop
    EndIf
    Next
    FileWriteLine($hFile, $aOut_h[$i + 1] & ';' & $aOut_h[$i] & ';' & $aOut_h[$i + 2] & ';' & $aOut_h[$i + 3] & $sTmp)
    Next
    FileClose($hFile)
    EndIf
    EndIf

    [/autoit]
  • jetzt sind über 99% richtig konvertiert, leider übersah ich, dass es zwei Arten von Kommentaren gibt, sorry

    Code
    //#define RAMPE_P1_AUF 		12,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/
    //Bsp.: #define AE1_0		326,B_EEPROM_WORD/*1, ,#SYSTEMEINSTELLUNGEN#EINGANG#ANALOG*/

    Die erste Zeile wird richtig abgehandelt, das zweite Kommentar wird noch nicht erkannt.
    Wollte meine ersten Kenntnisse gleich testen, bräuchte aber nochmals deine Hilfe.


    Vielen Dank
    Michael

    • Offizieller Beitrag

    So, jetzt aber:

    Spoiler anzeigen
    [autoit]


    $sData_h = FileRead(@ScriptDir & '\test.h')
    $aOut_h = StringRegExp($sData_h, '(?:\A|\r\n)#define\s+(\S+?)\s+(\d+),.+/\*(.+),(.+),.+/', 3)
    $sData_c = FileRead(@ScriptDir & '\test.c')
    $aOut_c = StringRegExp($sData_c, '.+\((.+?, \d+)\);', 3)
    If IsArray($aOut_h) Then
    $hFile = FileOpen(@ScriptDir & '\test_out.csv', 2)
    If $hFile <> -1 Then
    FileWriteLine($hFile, 'Adresse; Bezeichnung; Faktor; Einheit; akt. Wert; Wert1; Wert2; Wert3')
    For $i = 0 To UBound($aOut_h) - 1 Step 4
    $sTmp = ''
    For $j = 0 To UBound($aOut_c) - 1
    If StringInStr($aOut_c[$j], $aOut_h[$i]) Then
    $sTmp = ';' & StringMid($aOut_c[$j], StringInStr($aOut_c[$j], ', ') + 2)
    ExitLoop
    EndIf
    Next
    FileWriteLine($hFile, $aOut_h[$i + 1] & ';' & $aOut_h[$i] & ';' & $aOut_h[$i + 2] & ';' & $aOut_h[$i + 3] & $sTmp)
    Next
    FileClose($hFile)
    EndIf
    EndIf

    [/autoit]
  • ein ganz großes DANKESCHÖN an Oscar, der mir geholfen hat diese Skript zu entwickeln, an dem ich sonst noch die ganze Woche herumgetüftelt hätte. Die Funktionalität ist 100% erfüllt, nur noch ein kleiner Schönheitsfehler, den ich mich fast nicht mehr traue zu posten, da ich schon so viel Hilfe bekommen habe.

    Code
    #define RAMPE_P1_AUF		12,B_EEPROM_2BYTE_U/*0.1,s,#PWM#ESX#RAMPE*/

    In der CSV-Datei erscheint der Faktor 0.1 (...U/*0.1,s,#...).
    Damit Excel diesen Faktor als Zahl erkennt sollte der Faktor als 0,1 in der CSV-Datei abgespeichert werden.
    Wie kann ich diesen Punkt in ein Komma umwandeln?

    Wie gesagt, mir wurde zu 100% geholfen und dieser Thread kann geschlossen werden.

    Viele Grüße
    Michael

    • Offizieller Beitrag

    Ist schnell gemacht:

    Spoiler anzeigen
    [autoit]


    $sData_h = FileRead(@ScriptDir & '\test.h')
    $aOut_h = StringRegExp($sData_h, '(?:\A|\r\n)#define\s+(\S+?)\s+(\d+),.+/\*(.+),(.+),.+/', 3)
    $sData_c = FileRead(@ScriptDir & '\test.c')
    $aOut_c = StringRegExp($sData_c, '.+\((.+?, \d+)\);', 3)
    If IsArray($aOut_h) Then
    $hFile = FileOpen(@ScriptDir & '\test_out.csv', 2)
    If $hFile <> -1 Then
    FileWriteLine($hFile, 'Adresse; Bezeichnung; Faktor; Einheit; akt. Wert; Wert1; Wert2; Wert3')
    For $i = 0 To UBound($aOut_h) - 1 Step 4
    $sTmp = ''
    For $j = 0 To UBound($aOut_c) - 1
    If StringInStr($aOut_c[$j], $aOut_h[$i]) Then
    $sTmp = ';' & StringMid($aOut_c[$j], StringInStr($aOut_c[$j], ', ') + 2)
    ExitLoop
    EndIf
    Next
    FileWriteLine($hFile, $aOut_h[$i + 1] & ';' & $aOut_h[$i] & ';' & StringReplace($aOut_h[$i + 2], '.', ',') & ';' & $aOut_h[$i + 3] & $sTmp)
    Next
    FileClose($hFile)
    EndIf
    EndIf

    [/autoit]

    Wenn das Problem gelöst ist, kannst Du Deinen ersten Post bearbeiten und den Präfix von "offen" auf "gelöst" ändern.

  • so, ich habe nun mit dem RegExpbuddy herumexperementiert und langsam werden die RegEx befehle verständlicher.
    Respekt, wirklich.
    Leider konnte ich das letzte Problem selbstständig nicht lösen. Es viel mir auch erst auf, nachdem ich alles für funktionsfähig erklärt habe.

    in der .c-Datei gibt es zwei Strukturen

    Code
    s32_error |= ba_llt_writeTempEEPROM(PWM56_MIN, 200);
    s32_error |= ba_llt_writeTempEEPROM(PWM56_MAX, 800);
    s32_error |= ba_llt_writeTempEEPROM(RAMPE_P1_AUF,1);
    s32_error |= ba_llt_writeTempEEPROM(RAMPE_P1_AB,1);

    Einmal mit Leerzeichen am Ende und einmal ohne.
    Es wird nur der Wert mit Leerzeichen übernommen.
    Es ist nur eine winzige Änderung nötig, aber bisher zerschieße ich immer den hinteren Teil der Formatierung.

    Vielen Dank
    Michael