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%%)}}