Doppelte Zahlen

  • Moin Moin.

    Ich habe acht CSV-Datei. Wie kann ich mir die doppelten Zahlen in den Dateien anzeigen lassen?

    Die Zahlen haben unterschiedliche Längen und sind in den CSV-Dateien überall verteilt.

    Vielen Dank an dieser Stelle bereits für evtl. Hilfen.

    LG, Lina.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

    Einmal editiert, zuletzt von Alina (20. Oktober 2010 um 18:54)

  • Moin Alina,

    Frei aus der Hand, ohne es getestet zu haben:

    [autoit]

    #include <Array.au3>
    Local $sPfad, $sText, $aMatch
    $sPfad = FileOpenDialog("CSV Datei","","CSV Dateien (*.csv)")
    $sText = FileRead($sPfad)

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

    $aMatch = StringRegExp($sText,"(?s)(\d+).+\1",3)
    _ArrayDisplay($aMatch)

    [/autoit]
  • War auch mein erster Gedanke aber so funktioniert es nicht da die RegEngine erst nach einem kompletten Match weitersucht anstatt darin.
    Hatte hier dazu auch mal eine Frage gestellt wo leider bisher keiner eine Antwort wusste (>>Thread<<).
    Daher funktioniert das ganze mit folgendem String nicht:

    Code
    sfsdgösdglsgdg223fsdfdsölfs,dfdsf535dasdasd678dasdsadsad
    fsdfdsfsdlk223fsdfdsfsdf535dasdasdasd


    Es würde nur die 223 gefunden (und die 5 - aber das liegt nur daran da um den Match jeweils ein \D fehlt).

    Daher mal ein Workaround (hätte es auch lieber rein mit StringRegExp gelöst):

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    $String = "sfsdgösdglsgdg223fsdfdsölfs,dfdsf535dasdasd678dasdsadsad" & @CRLF & "fsdfdsfsdlk223fsdfdsfsdf535dasdasdasd"

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

    $aRet = FindDoubleNumbers($String)
    _ArrayDisplay($aRet)

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

    Func FindDoubleNumbers($String)
    Local $oD = ObjCreate('Scripting.Dictionary'), $oRet = ObjCreate('Scripting.Dictionary')
    Local $aA = StringRegExp($String,"(\d+)",3)
    If @error Or (Not IsArray($aA)) Then Return SetError(1,0,0)
    For $i In $aA
    If $oD.Exists($i) Then
    $oRet.Add($i, 0)
    Else
    $oD.Add($i, 0)
    EndIf
    Next
    Return $oRet.Keys()
    EndFunc

    [/autoit]
  • AspirinJunkie:
    Workaround? Das ist genau das was ich suchte. Danke.

    DANKE an alle die geholfen haben.

    L I N A

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

  • Ist es besser mit Objekten zu arbeiten?
    Ich komme damit nämlich net so richtig damit klar. :whistling:

    Meine Version

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    $String = "sfsdgösdglsgdg223fsdfdsöl3fs,dfdsf535dasdasd678dasdsadsad" & @CRLF & "fsdfdsf3sdlk223fsdfdsfsdf535dasdasdasd"

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

    $aRet = FindDoubleNumbers($String)
    _ArrayDisplay($aRet)

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

    Func FindDoubleNumbers($String)
    Local $aA = StringRegExp($String,"(\d+)",3)
    Local $avArray[1]
    If @error Or (Not IsArray($aA)) Then Return SetError(1,0,0)
    For $i In $aA
    if _ArraySearch($avArray, $i) = -1 Then _ArrayAdd($avArray,$i)
    Next
    Return $avArray

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

    EndFunc

    [/autoit]

    MfG
    Der_Doc

  • Naja es benötigt weniger Code (_ArraySearch und _ArrayAdd sind ja auch nur ausgelagerter Code) und sollte, zumindestens bei großen Strukturen performanter sein.
    Einen Zwang dazu gibt es natürlich nicht - ich komm damit besser klar.
    Das ist aber keine generelle Aussage über Vorteile von Objekten gegenüber Arrays. Das ist anwendungsspezifisch.

    Desweiteren müsstest du aber eh erst noch dein Skript anpassen da es auch die Zahl 678 ausgibt welche aber nur 1x im String vorkommt und Array[0] bleibt immer leer. ;)

  • Hab hier mal ne Funktion gebastelt. Vllt. nicht optimal programmiert, aber sie funktioniert :D

    [autoit]

    Func _ListDoubleNumbers($sText)
    Local $a = 1, $b = 0, $c = 0
    Local $aMatches[1]
    Local $aRegEx = StringRegExp($sText, "(\d+)", 3)
    Local $aTest = _ArrayUnique($aRegEx)
    Do
    For $b = 0 To UBound($aRegEx) - 1
    If ($aTest[$a] = $aRegEx[$b]) And ($a <> ($b+1)) Then $c += 1
    Next
    If $c = 1 Then _ArrayAdd($aMatches, $aTest[$a])
    $c = 0
    $a += 1
    Until $a = $aTest[0]
    Return $aMatches
    EndFunc

    [/autoit]
  • AspirinJunkie Ok ich gebe mich geschlagen. :rolleyes:

    Zu meiner Ehre hier noch das korregierte Skript aber es beginnt trotzdem bei 1 und ich finde es auch net so übel ;)
    Meine Frage zwecks den Objekten war nicht so gemeint ob es schneller oder schöner ist sonder ob es proktikabler ist.
    Ich würde das nämich auch gerne öfter nutzen aber vertehe leider den Aufbau net und deswegen tue ich mich damit so schwer. :huh:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    $String = "sfsdgösdglsgdg223fsdfdsöl3fs,dfdsf535dasdasd678dasdsadsad" & @CRLF & "fsdfdsf3sdlk223fsdf223dsfsdf535dasdasdasd"

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

    $aRet = FindDoubleNumbers($String)
    _ArrayDisplay($aRet)

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

    Func FindDoubleNumbers($String)
    Local $aA = StringRegExp($String,"(\d+)",3)
    Local $avArray[1]
    If @error Or (Not IsArray($aA)) Then Return SetError(1,0,0)
    For $i In $aA
    if UBound(_ArrayFindAll($aA, $i)) >= 2 then
    if _ArraySearch($avArray, $i) = -1 Then _ArrayAdd($avArray,$i)
    EndIf
    Next
    Return $avArray

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

    EndFunc

    [/autoit]

    MfG
    Der_Doc

  • Hallo,

    manchmal ist die AutoHotkey Hilfe etwas "großzügiger" als die AutoIt Hilfe:

    Zitat von AutoHotkey

    Look-ahead and look-behind assertions: The groups (?=...), (?!...), (?<=...), and (?<!...) are called assertions because they demand a condition to be met but don't consume any characters. For example, abc(?=.*xyz) is a look-ahead assertion that requires the string xyz to exist somewhere to the right of the string abc (if it doesn't, the entire pattern is not considered a match). (?=...) is called a positive look-ahead because it requires that the specified pattern exist. Conversely, (?!...) is a negative look-ahead because it requires that the specified pattern not exist. Similarly, (?<=...) and (?<!...) are positive and negative look-behinds (respectively) because they look to the left of the current position rather than the right. Look-behinds are more limited than look-aheads because they do not support quantifiers of varying size such as *, ?, and +.


    Der folgende RegEx liefert zum gegebenen Zahlenbeispiel alle Treffer, manche allerdings mehrfach, wenn die Bedingung mehrfach erfüllt wird:

    [autoit]

    #include <Array.au3>
    $String = "sfsdgösdglsgdg223fsdfdsöl3fs,dfdsf535dasdasd678dasdsadsad" & @CRLF & _
    "fsdfdsf3sdlk223fsdf223dsfsdf535dasdasdasd"
    ; Um auch für den Fall, das Matches ganz am Anfang oder am Ende vorkommen,
    ; das Regexpattern schlicht halten zu können, umgeben wir den Suchbegriff
    ; mit "Nichttrefferzeichen"
    $aRet =StringRegExp("$" & $String & "$", "(?s)\D(\d+)\D(?=.*\D\1\D)", 3)
    _ArrayDisplay($aRet)

    [/autoit]
    • Offizieller Beitrag

    Meine Frage zwecks den Objekten war nicht so gemeint ob es schneller oder schöner ist sonder ob es proktikabler ist.


    Entscheide selbst:

    kurzer Vergleich Array/Dictionary-Objekt
    [autoit]

    ; === Erstellen Array und Dictionary-Objekt
    ; === 2D-Array, da Dictionary eine Schlüssel-Wert Verwaltung ist
    Local $array[1][2], $oSD = ObjCreate('Scripting.Dictionary')
    ; === Array wird über Index angesprochen
    ; === Dictionary wird direkt über den Schlüssel angesprochen

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

    ; === Werte eintragen
    ; === Array
    If $array[UBound($array)-1][0] <> '' Then ReDim $array[UBound($array)+1][2]
    $array[UBound($array)-1][0] = 'Schlüssel'
    $array[UBound($array)-1][1] = 'Wert'

    ; === Dictionary
    $oSD.Add('Schlüssel', 'Wert')

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

    ; === Wert ausgeben
    ; === Array
    $index = _ArraySearch($array, 'Schlüssel')
    ConsoleWrite($array[$index][1] & @CRLF)

    ; === Dictionary
    ConsoleWrite($oSD.Item('Schlüssel') & @CRLF)

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

    ; === Wert löschen
    ; === Array
    $index = _ArraySearch($array, 'Schlüssel')
    _ArrayDelete($array, $index)

    ; === Dictionary
    $oSD.Remove('Schlüssel')

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

    ; === Überprüfen ob Schlüssel existiert
    ; === Array
    _ArraySearch($array, 'Schlüssel')
    If @error Then
    ConsoleWrite('Existiert nicht' & @CRLF)
    Else
    ConsoleWrite('Existiert' & @CRLF)
    EndIf

    ; === Dictionary
    If $oSD.Exists('Schlüssel') Then
    ConsoleWrite('Existiert' & @CRLF)
    Else
    ConsoleWrite('Existiert nicht' & @CRLF)
    EndIf

    [/autoit]

    Mehr findest du hier: Objekt: Scripting.Dictionary

  • @Großvater
    Da dank ich dir für den Denkanstoss.
    Zwar waren mir die Look-arounds schon bekannt und eingesetzt hab ich sie auch - allerdings nicht mit hier in Verbindung gebracht.
    Leider müsste man so wie es jetzt ist noch ein ArrayUnique über die Ergebnisliste laufen lassen.
    Ideal wäre man könnte die Lookarounds kombinieren.
    Z.B. könnte man noch einen negativen Lookbehind davor setzen so dass immer nur die 1. gleiche Zahl gefunden wird. Dann sollten die doppelten Einträge verschwinden. Habe verschiedene Methoden probiert aber konnte keine zum Laufen bekommen.
    Folgendes erscheint mir noch am logischsten aber funktioniert wie gesagt nicht:

    Code
    (?s)(?<!\D\1\D.*)\D(\d+)\D(?=.*\D\1\D)


    Ich vermute es liegt an der Backreference welche schon vor dem eigentlichen Match erscheint.
    Vielleicht könnte man noch mit Conditionals da etwas entsprechendes verschachteln aber da würde mir zu schnell die Übersicht im Pattern verloren gehen.

    @Der Doc
    Naja wie gesagt - die Bedienung von Objekten ist halt bisschen anders (Methoden und Attribute davon erreicht man durch den Punkt dahinter).
    BugFix' Beispiel sollte aber sicherlich gut für eine Übersicht sein.
    Gerade das Dictionary-Objekt kann Code ziemlich vereinfachen.

  • Laut dem Zitat von Großvater bezieht sich die Einschränkung mit den Quantifizierern aber lediglich auf Look-Behinds:

    Zitat

    Look-behinds are more limited than look-aheads because they do not support quantifiers of varying size such as *, ?, and +.


    Was natürlich ein weiterer Grund ist warum mein gewünschter Ansatz nicht funktioniert.

  • Also bei Lookbehinds funktioniert das Problemlos:

    [autoit]

    #include <Array.au3>
    $sText = _
    'Hallo113141414' & @CRLF & _
    'Hallo2ichhabenurtext' & @CRLF & _
    'Hallo3250825hierkommt text' & @CRLF

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

    $aMatch = StringRegExp($sText, "Hallo\d(?!\d+)", 3) ; Nur Zeilen mit "Hallo[ZAHL][KEINE ZAHLEN]" finden. [KEINE ZAHLEN] kommen nicht ins Ergebnis!
    ConsoleWrite(@error & @CRLF)
    _ArrayDisplay($aMatch)

    [/autoit]


    Hier übrigens nochmal die Funktion als String Variante, die deutlich schneller ist als die Array oder Objekt-Versionen ;)

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    $String = "sfsdgösdglsgdg223fsdfdsölfs,dfdsf535dasdasd678dasdsadsad" & @CRLF & "fsdfdsfsdlk223fsdfdsfsdf535dasdasdasd"

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

    $iTi = TimerInit()
    $aRet = FindDoubleNumbers($String)
    ConsoleWrite(TimerDiff($iTi) & @CRLF)
    _ArrayDisplay($aRet)

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

    $iTi = TimerInit()
    $aRet = FindDoubleNumbers_Str($String)
    ConsoleWrite(TimerDiff($iTi) & @CRLF)
    _ArrayDisplay($aRet)

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

    Func FindDoubleNumbers_Str($String)
    Local $sRet, $sAll
    Local $aA = StringRegExp($String, "(\d+)", 3)
    If @error Or (Not IsArray($aA)) Then Return SetError(1, 0, 0)
    For $i In $aA
    If StringInStr($sAll, "|" & $i & ">", 1) And Not StringInStr($sRet, "|" & $i & ">", 1) Then $sRet &= "|" & $i & ">"
    $sAll &= "|" & $i & ">"
    Next
    Return StringSplit(StringMid(StringReplace($sRet, ">", "", 0, 1), 2), "|",2)
    EndFunc ;==>FindDoubleNumbers_Str

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

    Func FindDoubleNumbers($String)
    Local $oD = ObjCreate('Scripting.Dictionary'), $oRet = ObjCreate('Scripting.Dictionary')
    Local $aA = StringRegExp($String, "(\d+)", 3)
    If @error Or (Not IsArray($aA)) Then Return SetError(1, 0, 0)
    For $i In $aA
    If $oD.Exists($i) Then
    $oRet.Add($i, 0)
    Else
    $oD.Add($i, 0)
    EndIf
    Next
    Return $oRet.Keys()
    EndFunc ;==>FindDoubleNumbers

    [/autoit]
    • Offizieller Beitrag


    Hier übrigens nochmal die Funktion als String Variante, die deutlich schneller ist als die Array oder Objekt-Versionen ;)


    Die String-Variante könnte man auch so schreiben:

    Spoiler anzeigen
    [autoit]


    Func FindDoubleNumbers_Str($String)
    Local $sRet, $aA = StringRegExp($String, "(\d+)", 3)
    If @error Or (Not IsArray($aA)) Then Return SetError(1, 0, 0)
    For $i In $aA
    $String = StringReplace($String, $i, '', 0, 2)
    If @extended > 1 Then $sRet &= $i & "|"
    Next
    Return StringSplit(StringTrimRight($sRet, 1), '|', 2)
    EndFunc ;==>FindDoubleNumbers_Str

    [/autoit]

  • Die String-Variante könnte man auch so schreiben:
    [...]


    Hatte ich auch zuerst gedacht, aber lass deine Funktion mal mit so einem Teststring laufen:
    "2 245 245 245"

    Als Ergebnis erhälst du 2, die ja nicht wirklich doppelt vorkommt. Nur als Teil einer anderen Zahl.

  • ... Einzeiler:

    [autoit]

    #include <Array.au3>
    $String = "535sfsdgösdglsgdg223fsdfdsölfs,dfdsf535dasdasd678da535" & @CRLF & _
    "2sdsads2adfsdf223dsfsdlk223fsdfdsfsdf535dasd3asdasd232"
    $aDouble = StringRegExp(StringRegExpReplace("$" & $String & "$", "(?s)\D(\d+)\D(?=(?:.*\D\1\D){2})", ""), _
    "(?s)\D(\d+)\D(?=.*\D\1\D)", 3)
    _ArrayDisplay($aDouble, "Doppelte")

    [/autoit]