Suchen eines Strings und Ersetzen der ganzen Zeile, dabei doppelte Einträge löschen

  • Hallo,

    ich habe da ein kleines Problem. Ich muss eine Zeile in die Datei @SystemDir & "\drivers\etc\services" schreiben.
    Der Aufbau der Datei "services" ist: <service name> <port number>/<protocol> [aliases...] [#<comment>]
    Anhand des <service name> durchsuche ich die Datei und ersetze ggfs. einen vorhandenen Eintrag. Leider kann es vorkommen, dass der <service name> mehrfach eingetragen ist. Dies sollte zwar nicht sein, aber passiert, wenn man eine Software mehrfach installiert... Manchmal kommt es sogar vor, dass die Einträge der <port numbers/protocol> unterschiedlich sind, ein Kommentar vorhanden ist oder nicht...

    Derzeit kann ich zwar alle vorhandenen Einträge (basierend auf dem <service name>) finden und ersetzen, aber irgendwie funktioniert das Löschen der doppelten Einträge nicht.
    Im angehängten Skript habe ich die Lösch-Zeilen 'mal mit ";~" auskommentiert, vielleicht habt Ihr ja eine Idee dazu...
    (Der Einfachheit halber habe ich mir die services Datei ins Skriptverzeichnis kopiert, dann testet es sich besser... s. Skript)

    [autoit]

    ;*******************************************************************************************************************************
    #include <File.au3>

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

    $srcfile=@ScriptDir & "\services"
    $replaceString="sapmsFC1"&@TAB&"3680/tcp"&@TAB&"# SAP System Messaging Service Port"
    $searchString="sapmsFC1"

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

    Search_And_Replace ($srcfile, $searchString, $replaceString, 1)

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

    func Search_And_Replace ($s_file, $s_searchString, $s_replaceString, $b_DeleteDuplicates)
    ; $s_file = filename
    ; $s_searchString = string to search in file
    ; $s_replaceString = string to replace the searched string in file
    ; $b_DeleteDuplicates = flag, value 0=no or 1=yes, to deletes all duplicate lines of the search string or not,
    Dim $aLines [1000]
    Dim $stringCount

    $sfile=FileOpen($s_file, 0)

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

    for $i = 1 to _FileCountLines($s_file)
    $readline = FileReadLine($sfile, $i)
    if StringInStr($readline, $s_searchString, 2) Then
    $stringCount += 1
    $aLines [$stringCount] = $i
    ;MsgBox(0, "String found!", "The String " & $s_searchString & " is found in line: " & $i)
    _FileWriteToLine($s_file, $i, $s_replaceString, 1)
    EndIf
    Next

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

    ;~ Does not work, deletes only one of the wihshed lines and some other :-(...
    ;~
    ;~ if $b_DeleteDuplicates = 1 Then
    ;~ for $j=1 To $stringCount + 1
    ;~ MsgBox(0, "number", $stringCount)
    ;~ _FileWriteToLine($s_file, $aLines[$j], "", 1)
    ;~ Next
    ;~ EndIf

    ;MsgBox(0,"", $s_searchString & " entry does not exist!")
    FileClose($sfile)

    EndFunc
    ;*******************************************************************************************************************************

    [/autoit]

    Hier Suchen und Ersetzten habe ich zwar eine Suchen&Ersetzen gefunden, allerdings muss dafür dann die ganze Zeile identisch sein... Vielleicht ist es auch tatsächlich besser eine Tmp-Datei zu nutzen... ich bin für jeden Vorschlag offen...

    Beispiel-Auszug aus services Datei:

    mfg
    Axel

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

    Einmal editiert, zuletzt von ahe (9. April 2009 um 12:18)

  • Mein Vorschlag:

    [autoit]

    ;*******************************************************************************************************************************
    #include <File.au3>

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

    $srcfile = @ScriptDir & "\services"
    $replaceString = "sapmsFC1" & @TAB & "3680/tcp" & @TAB & "# SAP System Messaging Service Port"
    $searchString = "sapmsFC1"

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

    Search_And_Replace($srcfile, $searchString, $replaceString, 1)

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

    Func Search_And_Replace($s_file, $s_searchString, $s_replaceString, $b_DeleteDuplicates)
    ; $s_file = filename
    ; $s_searchString = string to search in file
    ; $s_replaceString = string to replace the searched string in file
    ; $b_DeleteDuplicates = flag, value 0=no or 1=yes, to deletes all duplicate lines of the search string or not,
    Local $stringCount
    $sfile = FileOpen($s_file, 0)

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

    For $i = 1 To _FileCountLines($s_file)
    $readline = FileReadLine($sfile, $i)
    If StringInStr($readline, $s_searchString, 2) Then
    $stringCount += 1
    ;MsgBox(0, "String found!", "The String " & $s_searchString & " is found in line: " & $i)
    If $stringCount > 1 Then
    _FileWriteToLine($s_file, $i, "", 1)
    Else
    _FileWriteToLine($s_file, $i, $s_replaceString, 1)
    EndIf
    EndIf
    Next
    FileClose($sfile)
    EndFunc ;==>Search_And_Replace
    ;*******************************************************************************************************************************;

    [/autoit]

    Habs getestet, es ist kürzer und funktioniert! :D

    Gruß Ashpool

    Gruß Ashpool

    Zitat von mir

    Bin immer wieder erstaunt, wie begrenzt ein Horizont sein kann.

  • Hallo Ashpool,

    vielen Dank für Deine Hilfe.

    Wenigstens war ich auf dem richtigen Weg, nur dann wollte ich es unnötig kompliziert machen :)

    Noch mal Danke
    Axel

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

  • Keine Ursache, gern geschehen. :)

    Eine Kleinigkeit ist mir noch aufgefallen, die Reservierung der Variablen $StringCount sollte besser so aussehen:

    [autoit]

    Local $stringCount = 0

    [/autoit]


    um $StringCount mit dem Wert 0 zu initialisieren, sonst könnte es bei einer möglichen Erweiterung, die auf den Wert 0 testet, zu unerwarteten Problemen kommen.

    Gruß Ashpool

    Gruß Ashpool

    Zitat von mir

    Bin immer wieder erstaunt, wie begrenzt ein Horizont sein kann.

  • Hallo Ashpool,

    ein kleines Problem noch. So wie es aussieht, werden die Einträge zwar ersetzt, allerdings werden nicht alle doppelten Einträge gelöscht.
    Ich vermute es liegt an der Anzahl der aufeinanderfolgenden gleichen Einträge.

    Ergebnis:

    Erst bei einem weitren Lauf des Skripts verschwindet der letzte doppelte Eintrag...

    mfg
    Axel

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

  • ein kleines Problem noch. So wie es aussieht, werden die Einträge zwar ersetzt, allerdings werden nicht alle doppelten Einträge gelöscht.


    Oh ja, wenn eine Zeile gelöscht wird, ist die nächste bearbeitete Zeile ja eigentlich erst die übernächste.
    Wenn wir die Zeilen von hinten durchgehen, sollte das Problem gelöst sein.

    [autoit]

    For $i = _FileCountLines($s_file) to 1 step -1

    [/autoit]

    Probier mal!

    Gruß Ashpool

    Gruß Ashpool

    Zitat von mir

    Bin immer wieder erstaunt, wie begrenzt ein Horizont sein kann.

  • Hi,

    andere Lösung mit Möglichkeit der Nutzung von $b_DeleteDuplicates und vorheriges Sichern der Services Datei:

    [autoit]


    #include <file.au3>
    #include <array.au3>
    #include <date.au3>
    Global $arecords
    $srcfile = @ScriptDir & "\services"
    $replaceString = "sapmsFC1" & @TAB & "3680/tcp" & @TAB & "# SAP System Messaging Service Port"
    $searchString = "sapmsFC1"
    Search_And_Replace($srcfile, $searchString, $replaceString, 1)
    Func Search_And_Replace($s_file, $s_searchString, $s_replaceString, $b_DeleteDuplicates)
    ; $s_file = filename
    ; $s_searchString = string to search in file
    ; $s_replaceString = string to replace the searched string in file
    ; $b_DeleteDuplicates = flag, value 0=no or 1=yes, to deletes all duplicate lines of the search string or not,
    Local $stringCount
    _FileReadToArray ($srcfile, $arecords)
    For $x = 1 to UBound ($arecords) - 1
    If StringInStr ($arecords [$x], $searchstring,2) <> 0 Then $arecords [$x] = $replacestring
    Next
    If $b_DeleteDuplicates = 1 Then _Array2DDblDel ($arecords)
    FileCopy ($s_file, $s_file & "_" & StringReplace (_NowDate (), ".","") & "_" & StringReplace (_NowTime (), ":","") & ".bak")
    $file = FileOpen ($s_file, 2)
    For $x = 1 to UBound ($arecords) -1
    FileWriteLine ($file, $arecords [$x])
    Next
    FileClose ($file)
    EndFunc ;==>Search_And_Replace
    ;----------------------------------------------------------------------------------------------------------------------
    ; Function _Array2DDblDel(ByRef $ARRAY [, $CASESENS=0])
    ;
    ; Description - From an 1D/2D Array will delete double entries (2D -> combination by '[n][0]' to '[n][x]').
    ; - Autodetection 1D/2D Array
    ; - By using string, you can choose case sensitivity.
    ;
    ; Parameter $ARRAY: Array to sort
    ; optional $CASESENS: Case sensitivity off[0] or on[1] (default 0)
    ;
    ; Return Succes ByRef Array without doubles
    ; Count of doubles
    ; Failure 0 and set @error = 1; no array
    ;
    ; Author BugFix ([email='bugfix@autoit.de'][/email])
    ;----------------------------------------------------------------------------------------------------------------------
    Func _Array2DDblDel(ByRef $ARRAY, $CASESENS=0)
    Local $iDIM, $arTmp[1] = [''], $dbl = 0, $count = 0
    If ( Not IsArray($ARRAY) ) Then
    SetError(1)
    Return 0
    EndIf
    $Ubound2nd = UBound($ARRAY,2)
    If @error = 2 Then
    For $i = 0 To UBound($ARRAY)-1
    $dbl = 0
    For $k = 0 To UBound($arTmp)-1
    Switch $CASESENS
    Case 0
    If $arTmp[$k] = $ARRAY[$i] Then
    $dbl = 1
    $count += 1
    EndIf
    Case 1
    If $arTmp[$k] == $ARRAY[$i] Then
    $dbl = 1
    $count += 1
    EndIf
    EndSwitch
    Next
    If $dbl = 0 Then
    If $arTmp[0] = "" Then
    $arTmp[0] = $ARRAY[$i]
    Else
    ReDim $arTmp[UBound($arTmp)+1]
    $arTmp[UBound($arTmp)-1] = $ARRAY[$i]
    EndIf
    Else
    $dbl = 0
    EndIf
    Next
    Else
    ReDim $arTmp[1][$Ubound2nd]
    $arTmp[0][0] = ''
    $x = 0
    For $i = 0 To UBound($ARRAY)-1
    $dbl = 0
    $val = ''
    $valTmp = ''
    For $l = 0 To $Ubound2nd-1
    $val &= $ARRAY[$i][$l]
    Next
    For $k = 0 To UBound($arTmp)-1
    For $l = 0 To $Ubound2nd-1
    $valTmp &= $arTmp[$k][$l]
    Next
    Switch $CASESENS
    Case 0
    If $valTmp = $val Then
    $dbl = 1
    $count += 1
    EndIf
    Case 1
    If $valTmp == $val Then
    $dbl = 1
    $count += 1
    EndIf
    EndSwitch
    Next
    If $dbl = 0 Then
    If $x = 1 Then ReDim $arTmp[UBound($arTmp)+1][$Ubound2nd]
    For $l = 0 To $Ubound2nd-1
    If $arTmp[0][0] = '' Or $x = 0 Then
    $arTmp[0][$l] = $ARRAY[0][$l]
    If $l = $Ubound2nd-1 Then $x = 1
    Else
    $arTmp[UBound($arTmp)-1][$l] = $ARRAY[$i][$l]
    $x = 2
    If $l = $Ubound2nd-1 Then $x = 1
    EndIf
    Next
    Else
    $dbl = 0
    EndIf
    Next
    EndIf
    $ARRAY = $arTmp
    Return $count
    EndFunc ; ==>_ArrayDblDel

    [/autoit]

    _Array2DDblDel komt von BugFix. [edit: Code geändert]

    ;-))

    Stefan

    7 Mal editiert, zuletzt von ojo (8. April 2009 um 15:26)

  • Hallo

    Ashpool: Es scheint zu funktionieren, muss aber noch ein paar weitere Tests machen und prüfen, ob nicht vielleicht ein paar andere Zeilen aus Versehen verschwinden...

    @ojo: Danke Dir, allerdings brauche ich da wohl etwas Zeit zum Durchsteigen... mit den Bugfix'schen Arrays wollte ich mich ohnehin 'mal beschäftigen...

    mfg
    Axel

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

  • Hab noch die Abfrage des $b_DeleteDuplicates-Parameters eingebaut: 8)

    Spoiler anzeigen
    [autoit]

    #include <File.au3>

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

    $srcfile = @ScriptDir & "\services"

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

    $replaceString = "sapmsFC1" & @TAB & "3680/tcp" & @TAB & "# SAP System Messaging Service Port"
    $searchString = "sapmsFC1"

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

    Search_And_Replace($srcfile, $searchString, $replaceString, 1) ; Ersetzen und Duplikate entfernen
    ;Search_And_Replace($srcfile, $searchString, $replaceString) ; Ersetzen, Duplikate behalten
    ;Search_And_Replace($srcfile, $searchString, $replaceString, 0) ; -- " --

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

    Func Search_And_Replace($s_file, $s_searchString, $s_replaceString, $b_DeleteDuplicates = 0)
    ; $s_file = filename
    ; $s_searchString = string to search in file
    ; $s_replaceString = string to replace the searched string in file
    ; $b_DeleteDuplicates = flag, value 0=no (default) or 1=yes, to deletes all duplicate lines of the search string or not,
    Local $stringCount = 0
    $sfile = FileOpen($s_file, 0)

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

    For $i = _FileCountLines($s_file) to 1 step -1
    $readline = FileReadLine($sfile, $i)
    If StringInStr($readline, $s_searchString, 2) Then
    $stringCount += 1
    ;MsgBox(0, "String found!", "The String " & $s_searchString & " is found in line: " & $i)
    If $stringCount > 1 and $b_DeleteDuplicates Then
    _FileWriteToLine($s_file, $i, "", 1)
    Else
    _FileWriteToLine($s_file, $i, $s_replaceString, 1)
    EndIf
    EndIf
    Next
    FileClose($sfile)
    EndFunc ;==>Search_And_Replace

    [/autoit]

    Gruß Ashpool

    Gruß Ashpool

    Zitat von mir

    Bin immer wieder erstaunt, wie begrenzt ein Horizont sein kann.

  • Uuups, daran hatte ich gar nicht mehr gedacht... danke Dir...

    Die Tests sind bislang gut verlaufen, auch jetzt mit der letzten Änderung.

    @ojo: Dein Skript konnte ich bislang nicht testen, mache ich aber entweder heute Abend oder Morgen...

    mfg
    Axel

    Hallo ojo, das Skript funktioniert, allerdings bin ich bislang noch nicht so ganz durchgestiegen, danke noch einmal. Ich setze den Thread jetzt auf gelöst.

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

    Einmal editiert, zuletzt von ahe (9. April 2009 um 12:18)