version=2.7.1 vdate=13.02.2020 fname=lib_printf.bas ns=%NAMESPACE% fpath=/vba/functions ======[VBA] sprintf(), vsprintf()====== //Gibt eine anhand des Formatierungs-Strings format gebildete Zeichenkette zurück.((Beschreibung zitiert von http://php.net/manual/de/function.print-r.php))// ==Version %%version%% - %%vdate%%== {{..%%fname%%|Download %%fname%% (V-%%version%%)}} Von PHP bin ich mir die tolle Funktion sprintf() gewohnt. Diese vermisste ich schmerzlich im VBA. Immer alle Strings mit & zusammenzusetzen war einfach hässlich. Auf der Suche nach einer Lösung fand ich eine printf Implementierung auf der Seite [[http://www.freevbcode.com/ShowCode.asp?ID=5014|PrintF and Related Functions in VB]]. Das fand ich am Anfang auch ganz toll. Doch vermisste ich die Reihenfolge-Parameter aus PHP. Auch die Umsetzung ohne Reguläre Ausdrücke hat mich erstaunt. Darum habe ich mir in etwa 3 Stunden Arbeit selber sprintf() und vsprintf() aus PHP implementiert. \\ Später kahm dann noch die Formatierungsregeln etc. dazu. Hier nun das Resultat. Erweiterungen findet ihr unter [[vba:functions:printf:addons]] ===== Definitionen ===== ==== Konstanten ==== Folgende Fehler-Codes sind definiert ^ Wert ^ Code ^ Beschreibung ^ | -2147221514 ((vbObjectError - 10))| ERR_INSUFFICIENT_PARAMS | Des Pattern hat mehr Platzhalter als Werte übergeben wurden | | -2147221515 ((vbObjectError - 11))| ERR_NOT_NUMBER | Es wird keine Zahl geliefert wo eine erwartet wird | | -2147221516 ((vbObjectError - 12))| ERR_INVALID | Das Format ist ungültig | ==== Funktionen ==== === sprintf() === Parst einen Pattern mit Werten (([[#Standartanwendung]])). Public Function sPrintF( _ ByVal iFormatString As String, _ ParamArray iParams() As Variant _ ) As String ***iFormatString ** Zu formatierender String ***Weitere Params** die dazugehörigen Werte === vsprintf() === Parse einen String mit den Werten als Array (([[#Beispiele für dir Funktion vsprintf()]])). Public Function vsPrintF( _ ByVal iFormatString As String, _ ByRef iParams() As Variant _ ) As String ***iFormatString ** Zu formatierender String ***iParams()** die dazugehörigen Werte als Array === printF_UserDefinedDateFormat() === Mit dem Property printF_UserDefinedDateFormat können benuzerdefinierte FOrmate hinterlegt werden. Siehe Beispiel [[#benutzerdefinierte_formate]] Public Property Get printF_UserDefinedDateFormat(Optional ByVal iNumber As Integer = 0) As String ==== Patterns ==== Die Formatierungen sind verscheidene Patterns. Die meiste habe ich aus PHP übernommen, andere aus Java. Der Aufbau ist folgednermasen %(Index)(Format)[Typ](Datum/ZeitFormat) ***//Index//** Die Angabe, um welchen übergebenen Werteparameter es sich handelt. Die Angabe ist Optional. Mögliche Werte: ''[Zahl]$'' Oder ''<''. Bei eihner Zahl gefolgt von einem $ Zeichen ist die Nummer des Paramters gemeint. Beginnend bei 1. Sprich ''%2$s'' bedeutet, dass der zweite Parameter ausgegeben wird. Bei < wird derselbe Wert verarbeitet wie beim Pattern davor. ''% Debug.Print sPrintF("Hallo %s", "Hans") Hallo Hans Debug.Print sPrintF("%s wiegt %f Kilo", "Hans", 76.5) Hans wiegt 76.5 Kilo Debug.Print sPrintF("%s wiegt %d Kilo", "Hans", 76.5) Hans wiegt 76 Kilo ==== Beispiel mit Reheinfolge ==== 'Mittels Positionszahl und $ kann angegeben werden, welcher Parameter gemeint ist. Es beginnt bei 1 ? sPrintF("%2$s wiegt %1$f Kilo", 76.5, "Hans") Hans wiegt 76.5 Kilo ? sPrintF("%1$s ist %1$s und %2$s ist %2$s", "Heute", "Morgen") Heute ist Heute und Morgen ist Morgen 'Mittels < kann angegeben werden, dass derselbe Parameter wir beim Pattern davor verwendet wird ? sPrintF("%s ist % ==== Beispiele für dir Funktion vsprintf() ==== Dim params(1) As Variant params(0) = "Heute" params(1) = "Morgen" Debug.Print vsPrintF("%1$s ist %1$s und %2$s ist %2$s", params) ==== sprintf() mit Formatierungen ==== 'Strings: ' [Hochkomma][Zeichen][Länge] = String mit [Zeichen] als Prefix auf [Länge] erweitert ' [Minus][Hochkomma][Zeichen][Länge] = dito, jedoch wird hinten mit [Zeichen] aufgefüllt ' [Punkt][Länge] = Der String wird auf [Länge] beschnitten ' [Minus][Punkt][Länge] = dito, jedoch von hinten debug.print sprintf("%1$s %1$'#6s %1$-'#6s %1$.3s %1$-.3s %1$q", "abcd") abcd ##abcd abcd## abc bcd 'abcd' 'Nummern: 'Float ' [Länge] = Vor dem Dezimaltrennzeichen wird mit [Länge] 0 aufgefüllt. ' [Punkt][Länge] = ANzahl Dezimalzeichen ' [Minus] = Das Vorzeichen wird mit immer angegeben debug.print sprintf("%1$f %1$6f %1$-.1f %1$.3f %1$d %<-d", 123.45) 123.45 000123.45 +123.5 123.450 123 +123 'Integer debug.print sprintf("%1$f %1$6f %1$-.1f %1$.3f %1$d", 123) 123 000123 +123.0 123.000 123 ==== sprintf() mit Datum ==== Der Datumspattern ist Zweiteilig. Zuerst kommt ein Buchstabe um anzugegebe, dass es dsich um ein Datum/Zeit handelt und dann ein Buchstabe für das Format. Da sist nicht meine Erfindung, das übernehme ich so von Java ([[http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html]]). Einzig beim Einleitenden Buchstaben habe ich noch das S hinzugefügt, um den Output SQL Konform zu schreiben. Somit haben T oder S als Einleitender Buchstabe, gefolgt vom Format ? sprintf("Heute ist %TA der % ==== Benutzerdefinierte Formate ==== Es können bis zu 10 benutzerdefinierte Formate hinterlegt werden. Dazu kann man die Funktion [[#printF_UserDefinedDateFormat]] verwenden. Die Formate können dann mittel U und dem Index abgerufenwerden printF_UserDefinedDateFormat(0) = "HH.NN" printF_UserDefinedDateFormat(1) = "d. MMMM YYYY" debug.print sPrintF("%Tu1 um % ==== Text-Formatierungen (Zeilenumbrüche und Tabulator) ==== 'Mit Zeilenumbruch \t und Tabulator \n debug.print sPrintF("%1$s\tist %1$s,\n%2$s\tist %2$s", "Heute", "Morgen") Heute ist Heute, Morgen ist Morgen 'Tabulator \t etc nicht parsen: den \ von \ mit einem \ markieren -> \\t debug.print sprintf("[\\t]\t%s", "ist ein Tabulator") [\t] ist ein Tabulator 'um nur diese Formatierungen umzuschreiben kann man auch ohne Paramter arbeiten debug.print sprintf("item:\tPunkt1") item: Punkt1 ===== Code ===== {{..%%fname%%|Download %%fname%% (V-%%version%%)}}