Tausender Trennzeichen - es doch bestimmt auch eleganter ...

  • Moin Moin,

    für aktuelles Projekt brauchte ich eine Funktion zur Formatierung von Zahlen.
    Konkret wollte ich Tausender-Trennzeichen, also statt

    123456789 wollte ich 123.456.789

    Ich habe ein wenig die Suche hier gequält und die "_StringAddThousandsSep" Funktion gefunden ... die aber nicht mehr bei AutoIt dabei ist - und die sah mir doch zu übertrieben aus.
    Naja, meine Lösung funktioniert, es geht aber ja wahrscheinlich viel eleganter oder?

    Ich habe mir zwar die Hilfe von "StringRegExpReplace" angesehen ... aber ganz ehrlich, das mit den Suchausdrücken und den geschweiften Klammern habe ich nicht verstanden ...

    Naja, hier meine Version:

    Spoiler anzeigen
    [autoit]

    #include <array.au3>

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

    Func _AddThousandDot($iZahl)
    Local $aZahl[1] ; Array
    Local $sZahl ; String
    Local $iZaehler ; Integer
    $sZahl = String($iZahl) ; Ersteinmal in einen String wandel
    If $sZahl = "" Then ;Ups, das Ding war leer!
    SetError(1)
    Return 1
    EndIf
    ;Nun bauen wir ein Array
    ; $aZahl[0] enthält die Anzahl der Elemente
    ; $aZahl[x] die jeweilige Stelle
    For $i = 1 To StringLen($sZahl) Step 1
    _ArrayAdd($aZahl,StringMid($sZahl,$i,1))
    $aZahl[0] = $aZahl[0] + 1
    Next
    $iZaehler = 0
    $sZahl = ""
    ;Nun bauen wir die Zahl Rückwärts wieder zusammen
    For $i = $aZahl[0] To 1 Step -1
    $iZaehler = $iZaehler + 1 ; Stellen mitzählen!
    $sZahl = $aZahl[$i] & $sZahl
    If $iZaehler = 3 And $i <> 1 Then ;Hui, die dritte Stelle - aber nicht die letzte!
    $sZahl = "." & $sZahl ; einen Punkt dazu
    $iZaehler = 0 ; und neu mit Zählen anfangen
    EndIf
    Next
    Return $sZahl
    EndFunc

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

    MsgBox(0,"ACHTUNG!","Gleich geht es los - diese Fenster dient nur dem Zweck" & @CRLF & _
    "das das Script vollständig geladen wird bevor die Funktion aufgerufen wird")
    MsgBox(0,"Formatierte Zahlen",_AddThousandDot(1234567890) & @CRLF & _AddThousandDot(111222333))
    Exit

    [/autoit]

    Ich freue mich jetzt schon auf die kürzeste Lösung :D

    BLinz

  • [autoit]

    #include <String.au3>

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

    $Test = "12234567899,876"
    $Dec = StringRegExp($Test, "\,\d*", 1)
    $Test = StringRegExpReplace($Test, "\,\d*", "")
    $Test = StringRegExpReplace(_StringReverse($Test), "\d{3}", "\0.")
    If IsArray($Dec) Then
    $Result = _StringReverse($Test) & $Dec[0]
    Else
    $Result = _StringReverse($Test)
    EndIf
    If StringLeft($Result, 1) = "." Then $Result = StringTrimLeft($Result, 1)
    ConsoleWrite($Result & @LF)

    [/autoit]


    Nur ein Beispiel.

  • Oder hier die _StringAddThousandsSepEx:

    Spoiler anzeigen
    [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _StringAddThousandsSepEx
    ; Description ...: Returns the original numbered string with the Thousands delimiter inserted.
    ; Syntax.........: _StringAddThousandsSep($sString[, $sThousands = -1[, $sDecimal = -1]])
    ; Parameters ....: $sString - The string to be converted.
    ; $sThousands - Optional: The Thousands delimiter
    ; $sDecimal - Optional: The decimal delimiter
    ; Return values .: Success - The string with Thousands delimiter added.
    ; Author ........: SmOke_N (orignal _StringAddComma
    ; Modified.......: Valik (complete re-write, new function name), KaFu (copied from 3.3.0.0, as function is deprecated in newer AU versions)
    ; Remarks .......:
    ; Related .......:
    ; Link ..........;
    ; Example .......; Yes
    ; ===============================================================================================================================
    Func _StringAddThousandsSepEx($sString, $sThousands = -1, $sDecimal = -1)
    Local $sResult = "" ; Force string
    Local $rKey = "HKCU\Control Panel\International"
    If $sDecimal = -1 Then $sDecimal = RegRead($rKey, "sDecimal")
    If $sThousands = -1 Then $sThousands = RegRead($rKey, "sThousand")
    ;~ Local $aNumber = StringRegExp($sString, "(\d+)\D?(\d*)", 1)
    Local $aNumber = StringRegExp($sString, "(\D?\d+)\D?(\d*)", 1) ; This one works for negatives.
    If UBound($aNumber) = 2 Then
    Local $sLeft = $aNumber[0]
    While StringLen($sLeft)
    $sResult = $sThousands & StringRight($sLeft, 3) & $sResult
    $sLeft = StringTrimRight($sLeft, 3)
    WEnd
    ;~ $sResult = StringTrimLeft($sResult, 1) ; Strip leading thousands separator
    $sResult = StringTrimLeft($sResult, StringLen($sThousands)) ; Strip leading thousands separator
    If $aNumber[1] <> "" Then $sResult &= $sDecimal & $aNumber[1]
    EndIf
    Return $sResult
    EndFunc ;==>_StringAddThousandsSepEx

    [/autoit]

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

  • Danke Chip, die hatte ich auch gefunden - aber die war mir zu ... kompliziert / groß für ein paar Punkte in den Zahlen

    So, zu i2c ...
    Ähm (Kopf kratz)
    mal sehen:


    Zeile 4:

    [autoit]

    $Dec = StringRegExp($Test, "\,\d*", 1)

    [/autoit]


    \, = wir suchen ein Komma, und da ein Komma ein Sonderzeichen ist müssen wir es maskieren ....
    \d* = findet alle Ziffern
    1 = Gibt ein Array zurück ... mit der ersten Übereinstimmung ... [nachdenk] ... ein Array mit nur einem Wert?
    mhh also ein Array das alle Nachkommastellen inklusive des Kommas enthält?


    Zeile 5:

    [autoit]

    $Test = StringRegExpReplace($Test, "\,\d*", "")

    [/autoit]


    wir ersetzen in unerser $Test wie folgt:
    \, = die Kommas
    \d* = und alle Zahlen
    durch "" , also nichts. mmh wozu? ... Moment - oben haben wir die Nachkommastellen herausgesucht mit dem selben Suchstring .... dann schneiden wir hier die Nachkommastellen ab!


    Zeile 6:

    [autoit]

    $Test = StringRegExpReplace(_StringReverse($Test), "\d{3}", "\0.")

    [/autoit]


    Wir drehen unseren $Test String um und ersetzen
    \d{3} = 3 aufeinanderfolgende Zahlen?
    durch
    \0. = finde ich nicht in der Hilfe, ich vermute "die 3 aufeinanderfolgenden Zahlen + ein Punkt" ?


    Zeile 7:
    Wenn $Dec, welcher zu diesem Zeitpunkt ein Array mit den einzelnen zahlen ist ...dann Zeile 8


    Zeile 8:

    [autoit]

    $Result = _StringReverse($Test) & $Dec[0]

    [/autoit]


    Dann ist $Result
    $Test wieder Rückwärts -> 2 mal Rückwärts wäre wieder vorwärts
    und daran hängen wir ... die Nachkommastellen die wir in Zeile 4 herausgesucht haben ....

    Klar, Zeile 10 ist für den Fall das $Dec kein Array ist - was bedeutet das es keine Nachkommastellen gab ...
    Und Zeile 12 dient für den Fall das er uns einen führenden Punkt gesetzt hat, z.B. bei 6-stelligen Zahlen ...

    PUHHHHHHHH

    Ich glaube ich habs verstanden - nur dem "\0." noch nicht ....

    Zitat

    Der Text, der den gefundenen Text des regulären Ausdrucks ersetzen soll. Es können auch Gruppentext wie z. B. \0 - \9 (oder $0 - $9) als Rückverweise verwendet werden


    Also Rückverweis ... das Ergebnis der Suche ... "\d{3}" ... die 3 aufeinanderfolgenden Zahlen?

    Und StringRegExpReplace ersetzt nicht nur einmal sondern jedesmal wenn er 3 Zahlen finden bis zum Ende des Strings?

    Mhh, habe ich es richtig verstanden? Wenn ja, dann glaube ich wird "StringRegExpReplace" mein neuer Liebling .... :love:

    BLinz

  • So,

    ich hab meine Funktion auf einen Einzeiler(!) gekürzt, dank der kleinen Lehrstunde von i2c:

    [autoit]

    #include <String.au3>

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

    Func _AddThousandDotNEU($iZahl)
    Return StringRegExpReplace(_StringReverse(StringRegExpReplace(_StringReverse($iZahl),"\d{3}","\0.")),"(?<![0-9])\.","",1)
    EndFunc

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

    MsgBox(0,"Formatierte Zahlen",_AddThousandDotNEU(1234567890) & @CRLF & _AddThousandDotNEU(111222333))

    [/autoit]

    Am "(?<![0-9])\." musste ich ein wenig herumprobieren - warum ging es nicht mit "(?<!\d*)\." ? Ist \d nicht erlaubt in den ( ) ?

    BLinz

    09.11.2011 / 15:15: Habe die vergessende Include Anweisung noch nachgetragen (Danke Oscar)

    Nachtrag: Kleine Erklärung für Leute wie mich (vor 2h):


    • _StringReverse($iZahl) - Wir drehen die Variable $iZahl um
    • Ersetzen immer wenn wir 3 aufeinanderfolgende Zahlen finden ( "\d{3}" ) diese durch die selben 3 Zahlen mit einem nachfolgenden Punkt ( "\0." )
    • drehen die Variable wieder um ( _StringReverse )
    • und ersetzen jeden Punkt "." der keine Zahl von 0 bis 9 vor sich hat ( "(?<![0-9])\." ) mit "" = Nichts. Die 1 steht dafür das er nur einmal ersetzten soll.
  • Danke Chip, die hatte ich auch gefunden - aber die war mir zu ... kompliziert / groß für ein paar Punkte in den Zahlen

    Die Funktioen fängt halt auch Kommazahlen, negative Zahlen und nimmt wenn keine Trennwerte übergibts die Sprachspezifische Trennzeichen.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.