User Tools

Site Tools


vba:access:functions:persist

[VBA][Access] persist()

Eine Funktion für ein einfacher INSERT INTO…ON DUPLICATE UPDATE

Version 1.3.7 - 24.11.2015

Die Funktion eignet sich gut, um schnell eine kleine Änderung (Add /Update) auf eine Tabelle anhand des PrimaryKey auszuführen.

Die Funktion führt ein Insert aus, sofern der Primary-Key keine übereinstimmung gefunden hat. Ansonsten wird ein Update ausgeführt.

Download udf_persist.bas (V-1.3.7)

Definition

id = persist(table, feld-1, value-1 [,feld-2, value-2...[,feld-n, value-n]])
id = persist(table, array(feld1 [,feld2...[,feld#]]), array(value1 [,value2]...[,value#]]))
id = persist(table, dictionary)
id = persist(table, string)
Public Function persist( _
        ByVal iTableName As String, _
        ParamArray iExpressions() As Variant _
) As Variant
  • iTableName Name der Tabelle
  • iExpressions() Immer abwechselnd Feldname, Value
  • return PrimaryKey

Beispiele

Für die Auswertungen verwende ich [VBA][Access] printRs() und [VBA] print_r().

Ich habe mal die folgenden 2 Tabellen (Felder des PrimaryKey sind mit * markiert)

TBL_EXCHANGE
CCY_FROM* CCY_TO* EXCHANGE_VALUE
CHF EUR 1.2
CHF USD 1.01
TBL_USER
ID* VORNAME NACHNAME
1 Hans Müller
2 Susanne Keller
3 Kurt Sutter
4 Miriam Hablützel

Beispiele zum Verhalten der Funktion

Manipulation ohne AutoInkrement Wert

Public Sub testPersist()
printRs CurrentDb.OpenRecordset("tbl_exchange")
 
'Kurs CHF-GPB mit 2.1 eintragen
print_r persist("tbl_exchange", "ccy_from", "CHF", "ccy_to", "GBP", "exchange_value", 2.1)
printRs CurrentDb.OpenRecordset("tbl_exchange")
 
 
'Kurs nochmals eintragen, dieses mal mit 2.2. Der Aufruf bleibt gleich.
'Das wird den alten Kurs überschreiben, da die Kombination CHF-GBP bereits vorhanden ist
print_r persist("tbl_exchange", "ccy_from", "CHF", "ccy_to", "GBP", "exchange_value", 2.2)
printRs CurrentDb.OpenRecordset("tbl_exchange")
End Sub

Und das ist die Ausgabe. Man sieht, wie zuerst die Kombination CHF-GBP hinzugefügt wird und mit dem zweiten Aufruf von persist() verändert wird.

| CCY_FROM | CCY_TO | EXCHANGE_VALUE |
|----------|--------|----------------|
| CHF      | EUR    | 1.2            |
| CHF      | USD    | 1.01           |
<Long> 64
| CCY_FROM | CCY_TO | EXCHANGE_VALUE |
|----------|--------|----------------|
| CHF      | EUR    | 1.2            |
| CHF      | USD    | 1.01           |
| CHF      | GBP    | 2.1            |
<Long> 48
| CCY_FROM | CCY_TO | EXCHANGE_VALUE |
|----------|--------|----------------|
| CHF      | EUR    | 1.2            |
| CHF      | USD    | 1.01           |
| CHF      | GBP    | 2.2            |

Manipulation mit Autoinkrement Key

Public Sub testPersistUser()
printRs CurrentDb.OpenRecordset("tbl_users")
 
'Frau Keller heiratet und wechselt den Namen auf Meier
print_r persist("tbl_users", "id", "2", "nachname", "Meier")
printRs CurrentDb.OpenRecordset("tbl_users")
 
 
'Eine Frau Ruth Peter wird eingetragen. ID wird automatisch erstellt
print_r persist("tbl_users", "vorname", "Ruth", "nachname", "Peter")
printRs CurrentDb.OpenRecordset("tbl_users")
 
End Sub
| ID | VORNAME | NACHNAME  |
|----|---------|-----------|
| 1  | Hans    | Müller    |
| 2  | Susanne | Keller    |
| 3  | Kurt    | Sutter    |
| 4  | Miriam  | Hablützel |
<Long> 48
| ID | VORNAME | NACHNAME  |
|----|---------|-----------|
| 1  | Hans    | Müller    |
| 2  | Susanne | Meier     |
| 3  | Kurt    | Sutter    |
| 4  | Miriam  | Hablützel |
<Long> 64
| ID | VORNAME | NACHNAME  |
|----|---------|-----------|
| 1  | Hans    | Müller    |
| 2  | Susanne | Meier     |
| 3  | Kurt    | Sutter    |
| 4  | Miriam  | Hablützel |
| 5  | Ruth    | Peter     |

Beispiele zu den verschiedenen Anwendungsformaen

Die Folgenden Beispiele bewirken alle dasselbe Resultat. Ein Datensatz mit einem Namen und einer externen System-ID wird abgefüllt und kriegt eine neue ID. Danach wird dieser Record um das Geburtstdatum ergänzt. Am Ende sieht dann die Tabelle so aus

| ID | USER NAME  | BIRTHDAY   | SYSTEM-ID |
|----|------------|------------|-----------|
| 1  | Stefan Erb | 01.06.1972 | 123       |

String-Liste

'Neuen Datensatz erstellen
Dim newId As Long
newId = persist("T_USERS_INFO", "user name", "Stefan Erb", "system-id", 123)
'Datensatz anpassen
persist "t_users_info", "id", newId, "birthday", #6-1-1972#

2 Arrays (Feld-Array & Value-Array)

'Neuen Datensatz erstellen
Dim newId As Long
newId = persist("T_USERS_INFO", array("user name", "system-id"), array("Stefan Erb", 123))
'Datensatz anpassen, das Geburtsdatum ergänzen
persist "t_users_info", array("id", "birthday"), array(newId,  #6-1-1972#)

Dictionary

'Neuen Datensatz erstellen
Dim dict As New dictionary
dict.add "user name", "Stefan Erb"
dict.add "system-id", 123
 
Dim newId As Long
newId = persist("T_USERS_INFO", dict)
 
'Datensatz anpassen
dict.RemoveAll
dict.add "id", newId
dict.add "birthday", #6/1/1972#
persist "t_users_info", dict

Set-String

'Neuen Datensatz erstellen
'Anstelle von "" im String kann auch ' verwendet werden
Dim newId As Long
newId = (persist "T_USERS_INFO", "[user name]=""Stefan Erb"", [system-id] = 123")
'Datensatz anpassen
persist "t_users_info", "id=" & newId & ", birthday =  #6-1-1972#"

Code

udf_persist.bas
Attribute VB_Name = "udf_persist"
'-------------------------------------------------------------------------------
'File         : udf_persist.bas
'               Copyright mpl by ERB software
'               All rights reserved
'               http://wiki.yaslaw.info/dokuwiki/doku.php/vba/access/functions/persist
'Environment  : VBA 2010 +
'Version      : 1.3.7
'Name         : persist
'Author       : Stefan Erb (ERS)
'History      : 27.05.2014 - ERS - Creation
'               ...
'               09.02.2015 - ERS - Neuste Verionen der Libraries eingespielt, Code leicht berarbeitet
'               04.03.2015 - ERS - Fehler behoben
'               24.11.2015 - ERS - Fehler behoben
'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'   Die Funktion eignet sich gut, um schnell eine kleine Änderung (Add /Update) auf eine Tabelle anhand des PrimaryKey auszuführen.
'   Die Funktion führt ein Insert aus, sofern der Primary-Key keine übereinstimmung gefunden hat. Ansonsten wird ein Update ausgeführt.
'
'   INSERT INTO...ON DUPLICATE UPDATE
'   Geprüft wird nur auf den Primary Key einer Tabelle
'
'   1) Immer abwechselnd Feldname, Value
'   ------------------------------------
'   id = persist(table, feld1, value1 [,feld2, value2...[,feld#, value#]])
'   @example:   persist "my_table", "id", 34, "f_string", "abcd3", "f_date", now, "f_double", 234.5
'
'   2) Zwei gleich grosse Array. Der erste beinhaltet die Feldnamen, der Zweite die Werte
'   -------------------------------------------------------------------------------------
'   id = persist(table, array(feld1 [,feld2...[,feld#]]), array(value1 [,value2]...[,value#]]))
'   @example:   persist "my_table", array("id", "f_string"), array(34, "abcd3")
'
'   3) Ein oder mehrere Dictionary. dict.key => Feldnamen, dict.value => Wert
'   -------------------------------------------------------------------------
'   id = persist(table, dictionary)
'   @example:   persist "my_table", my_dictionary
'
'   4) Ein Set-String (ohne das Wort Set) wie man ihn für ein Update-SQL kennt
'   --------------------------------------------------------------------------
'   id = persist(table, string)
'   @example:   persist "my_table", "id = 34, [f_string] = 'abcd3', f_date = #1-12-2013#, f_double = 234.5"
'-------------------------------------------------------------------------------

 
Option Explicit
 
Public Const ERR_PERSIST_INVALID_ARGUMENT_COUNT = vbObjectError + 501   'Der ParamArray hat eine ungerade Anzahl Argumente
Public Const ERR_PERSIST_NO_PRIMARY_KEY = vbObjectError + 502           'Die Tabelle hat kein PrimaryKey
Public Const ERR_PERSIST_TO_MATCH_FIELDS_IN_PK = vbObjectError + 503    'Der Seek() muss ausgebaut werden, damit die bestehende Anzahl Felder des PK abgedeckt sind

Private Const dbAutoIncrField = 16
'/**
' * INSERT INTO...ON DUPLICATE UPDATE
' * Geprüft wird nur auf den Primary Key einer Tabelle
' *
' * @param  String      Name der Tabelle
' * @param  ParamArray  Hier sind verschiedene Kombnationen möglich: Siehe Module-Beschreibung
' * @return Variant     Primary
' */
Public Function persist( _
        ByVal iTableName As String, _
        ParamArray iExpressions() As Variant _
) As Variant
    'Die Auswertung der Parameters ist analog zu cDict. Darum verwende ich diese Funktion
    Dim pExpressions() As Variant:      pExpressions = CVar(iExpressions)
    Dim fieldsDict      As Object:      Set fieldsDict = uCaseDictKeys(cDictA(pExpressions))
 
    Dim db              As Object:      Set db = CurrentDb
    Dim tbl             As Object:      Set tbl = db.TableDefs(iTableName)
    'PrimaryKey Infos auslesen
    Dim pkInfo          As Object:      Set pkInfo = getPkInfo(tbl)
    'Kein PrimaryKey vorhanden
    If pkInfo!indexName = Empty Then Err.Raise ERR_PERSIST_NO_PRIMARY_KEY, "persit", "Table have no Primary Key"
    'Key mit Daten befüllen
    Dim keys() As Variant:  keys = pkInfo!fields.keys
    Dim KEY As Variant:     For Each KEY In keys
        If fieldsDict.exists(KEY) Then pkInfo!fields(KEY) = cast(fieldsDict(KEY), tbl.fields(KEY).type)
    Next KEY
 
    Dim pkValues() As Variant: pkValues = pkInfo!fields.items     'Bei LateBinding kann nicht mehr direkt über den Index auf die Itesm des Dictionary zugegriffen werden
    
    Dim pkCount As Long: pkCount = pkInfo!fields.count
    'Recordset öffnen und Eintrag anhand Primary key suchen
    Dim rs As Object: Set rs = tbl.OpenRecordset
    If tbl.Connect = "" Then    'Eigene Tabelle
        rs.index = pkInfo!indexName
        Select Case pkCount
            Case 1: rs.Seek "=", pkValues(0)
            Case 2: rs.Seek "=", pkValues(0), pkValues(1)
            Case 3: rs.Seek "=", pkValues(0), pkValues(1), pkValues(2)
            Case 4: rs.Seek "=", pkValues(0), pkValues(1), pkValues(2), pkValues(3)
            Case Else: Err.Raise ERR_PERSIST_TO_MATCH_FIELDS_IN_PK, "persits", "PrimaryKey have to many fields"
            '//TODO erweitern für grössere Indexe
        End Select
    Else    'Verlinkte Tabelle
        Dim find() As String: ReDim find(pkCount - 1)
        Dim i As Integer: For i = 0 To pkCount - 1
            find(i) = Application.BuildCriteria(keys(i), pkInfo("types")(keys(i)), pkValues(i))
        Next i
        rs.FindFirst Join(find, " AND ")
    End If
    'AddNew oder Edit, je nach noMatch
    If rs.NoMatch Then: rs.AddNew: Else: rs.Edit
    'Felder übertragen mit Ausnahme eines Autoinkrement Feldes
    keys = fieldsDict.keys
    For Each KEY In keys
        'nur übernehmen, wenn es nicht das autoInkrementFeld ist
        If Not UCase(KEY) = UCase(pkInfo!autoIncrFld) Then rs(KEY) = fieldsDict.item(KEY)
    Next KEY
 
    'Alles speichern, schliessen, abbauen
    If Not pkInfo!autoIncrFld = Empty Then: persist = rs(pkInfo!autoIncrFld): Else: persist = IIf(pkInfo!fields.count = 1, rs(keys(0)), True)
    rs.update: rs.Close
    Set rs = Nothing: Set tbl = Nothing: Set fieldsDict = Nothing:  Set pkInfo = Nothing: Set db = Nothing
End Function
 
'-------------------------------------------------------------------------------
'-- Private methodes
'-------------------------------------------------------------------------------

'/**
' * Liest den PrimaryKey einer Tabelle aus
' * @param  TableDef
' * @return Dictionary(autoIncrFld => String, fields => Dictionary(NAME => Empty), indexName => String)
' */
Private Function getPkInfo(ByRef iTbl As Object) As Object
    Static cachedPkDicts    As Object
    If cachedPkDicts Is Nothing Then Set cachedPkDicts = CreateObject("scripting.Dictionary")
 
    Dim tblName             As String:      tblName = UCase(iTbl.Name)
    If Not cachedPkDicts.exists(tblName) Then
        'CacheNode initialisieren
        Dim info As Object: Set info = cDict(Array("autoIncrFld", "fields", "types", "indexName"), Array(Empty, cDict(), cDict(), Empty))
        'Tabelle analysieren
        Dim pk As Object: For Each pk In iTbl.indexes
            If pk.Primary Then      'Primary Key durchgehen
                Dim fld As Variant: For Each fld In pk.fields
                    Dim KEY As String: KEY = UCase(fld.Name)
                    If (iTbl.fields(fld.Name).Attributes And dbAutoIncrField) Then info!autoIncrFld = fld.Name     'Prüfen auf autoIncrement
                    info!fields.add KEY, Empty
                    info("types").add KEY, iTbl.fields(fld.Name).type
                Next fld: Set fld = Nothing
                info!indexName = pk.Name
                Exit For
            End If
        Next pk
        cachedPkDicts.add tblName, info
    End If
    Dim keys() As Variant: keys = cachedPkDicts(tblName)!fields.keys
    Dim i As Long: For i = 0 To UBound(keys)
        cachedPkDicts(tblName)!fields(keys(i)) = Empty
    Next i
    Set getPkInfo = cachedPkDicts(tblName)
End Function
 
'/**
' * Setz alle Keys eines Dictionaries in Grossbuchstaben.
' * @param  Dictionary
' * @return Dictionary
' */
Private Function uCaseDictKeys(ByRef iDict As Object) As Object
    Dim keys() As Variant:  keys = iDict.keys
    Set uCaseDictKeys = CreateObject("scripting.Dictionary")
    Dim KEY As Variant: For Each KEY In keys
        uCaseDictKeys.add UCase(KEY), iDict(KEY)
    Next KEY
End Function
 
'/**
' * Castet ein Wert in das Format, dass die DB erwartet.
' * zB. rs.seek geht nicht mit String auf Long.
' * @param  Variant
' * @param  Integer     dao.DataTypeEnum
' * @return Variant
' */
Private Function cast(ByRef iValue As Variant, ByVal iVarType As Integer) As Variant
    Select Case iVarType
        Case 10:    cast = CStr(iValue)     'dbText
        Case 4:     cast = CLng(iValue)     'dbLong
        Case 3:     cast = CInt(iValue)     'dbInteger
        Case 1:     cast = CBool(iValue)    'dbBoolean
        Case 12:    cast = CStr(iValue)     'dbMemo
        Case 2:     cast = CByte(iValue)    'dbByte
        Case 6:     cast = CSng(iValue)     'dbSingle
        Case 5:     cast = CCur(iValue)     'dbCurrency
        Case 23:    cast = CDate(iValue)    'dbTimeStamp
'        Case dbBinary:
        Case 11:    cast = CLngPtr(iValue)  'dbLongBinary
        Case Else:  cast = iValue
    End Select
End Function
 
'-------------------------------------------------------------------------------
'-- Private libraries
'-------------------------------------------------------------------------------

'-- cDict V3.1.4
'/**
' * Wandelt verschiedene Formate in ein Dictionary um
' * http://wiki.yaslaw.info/dokuwiki/doku.php/vba/cast/cdic
' * @param  ParamArray
' * @return Dictionary
' */
Private Function cDict(ParamArray iItems() As Variant) As Object
    Dim items() As Variant:     items = CVar(iItems)
    Set cDict = cDictA(items)
End Function
 
'/**
' * Dito zu cDict(). Die Übergabe ist aber nicht ein ParamArray sondern ein Arry.
' * Dieser Aufruf wird vor allem im Einsatz in anderen Funktionen verwendet
' * http://wiki.yaslaw.info/dokuwiki/doku.php/vba/cast/cdic
' * @param  Array
' * @return Dictionary
' */
Private Function cDictA(ByRef iItems() As Variant) As Object
    'Cache RegExp um einSet-String zu zerlegen
    Static rxSetString As Object:               If rxSetString Is Nothing Then Set rxSetString = cRx("/(|lluN|eslaf|eurt|(['""#](?![\\,])).+?\1(?!\\)|[\d\.]*)\s*(?:>=|[:=])\s*((['""](?!\\)).+?\4(?!\\)|(\](?!\\)).+?\[(?!\\)|[\w\s-]+)/ig")
    Static rxCharsInStringToUnicode As Object:  If rxCharsInStringToUnicode Is Nothing Then Set rxCharsInStringToUnicode = cRx("/([\[\]\{\}'""=;,])/")
    Static rxStrings As Object:                 If rxStrings Is Nothing Then Set rxStrings = cRx("/(['""])([^\1]+?)\1/g")
    Set cDictA = CreateObject("scripting.Dictionary")
    Dim mc As Object
    Dim items() As Variant:                     items = CVar(iItems)
    Dim KEY As Variant, value As Variant
    Dim isList As Boolean
 
    If UBound(items) = -1 Then Exit Function
 
    'Prüfen ob 2 Parametetrs übergeben wurden
    If UBound(items) = 1 Then
        'Beide Parametrer sind Arrays -> Combine: Erster Array Keys, 2ter Values
        If IsArray(items(0)) And IsArray(items(1)) Then
            Dim keys() As Variant:      keys = items(0)
            Dim values() As Variant:    values = items(1)
            Dim delta As Long:          delta = LBound(keys) - LBound(values)
            ReDim Preserve values(LBound(values) To UBound(keys) + delta)
            Dim i As Integer: For i = LBound(keys) To UBound(keys)
                If Not cDictA.exists(keys(i)) Then cDictA.add keys(i), values(i + delta)
            Next i
            Exit Function
        End If
    End If
 
    'Alle Items durchackern
    Dim cnt As Integer:     cnt = 0
    Dim item As Variant:    For Each item In items
        'Dictionary
        If Not isList And TypeName(item) = "Dictionary" Then
            For Each KEY In item.keys
                If Not cDictA.exists(KEY) Then cDictA.add KEY, item.item(KEY)
            Next KEY
        'einsamer Array
        ElseIf Not isList And IsArray(item) Then
            For KEY = LBound(item) To UBound(item)
                If Not cDictA.exists(KEY) Then cDictA.add KEY, item(KEY)
            Next KEY
        'SetString
        ElseIf Not isList And Not IsArray(item) And Not IsObject(item) Then
            'Alle []{}'"=;, innerhalb eines Strings in Unicode parsen
            If rxStrings.test(item) Then
                Set mc = rxStrings.execute(item)
                For i = mc.count - 1 To 0 Step -1
                    Dim substr As String: substr = mc(i).subMatches(1)
                    Do While rxCharsInStringToUnicode.test(substr)
                        substr = rxCharsInStringToUnicode.replace(substr, CStr(char2unicode(rxCharsInStringToUnicode.execute(substr)(0))))
                    Loop
                    Dim dm As String: dm = mc(i).subMatches(0)
                    item = replaceIndex(item, dm & substr & dm, mc(i).firstIndex, mc(i).length)
                Next i
            End If
            If rxSetString.test(StrReverse(item)) Then
                Set mc = rxSetString.execute(StrReverse(item))
                Dim k As Variant: For k = mc.count - 1 To 0 Step -1
                    KEY = cV(unicodeDecode(StrReverse(mc(k).subMatches(2))))
                    value = cV(unicodeDecode(StrReverse(mc(k).subMatches(0))), "nb")
                    If Not cDictA.exists(KEY) Then cDictA.add KEY, value
                Next k
 
            Else
                GoTo DEFAULT        'Zuerst wollte ich diesen GoTo nicht haben. Aber StrReverse() wirft ein Fehler wenn ein Objekt übergeben wird. Darum konnte der Test nicht im ElseIf durchgeführt werden.
            End If
        'Alles andere geht in ein WertePaar.
        ElseIf cnt = 0 Or isList Then
DEFAULT:
            If cnt Mod 2 = 0 Then
                KEY = item
            ElseIf Not cDictA.exists(KEY) Then cDictA.add KEY, item
            End If
            isList = True
        End If
        cnt = cnt + 1
    Next
    'Falls es sich um eine nicht abgeschlossene Liste handelt
    If isList And cnt Mod 2 <> 0 Then If Not cDictA.exists(KEY) Then cDictA.add KEY, Empty
End Function
 
'-------------------------------------------------------------------------------
'--- LIBRARIES for cDict
'-------------------------------------------------------------------------------

''/**
'' * Castet ein String in was auch immer (Integer, Long, Date etc.)
'' * Datum in #..# oder Strings in '..',".." und [..] können geparst werden
'' * V1.0.0
'' * http://wiki.yaslaw.info/dokuwiki/doku.php/vba/cast/cvalue
'' * @param  String
'' * @return Varaint
'' */
'Private Function cValue(ByVal iString As String, Optional ByVal iHandling As cvHandling) As Variant
'    Static rxDelemitedString As Object
'    If rxDelemitedString Is Nothing Then Set rxDelemitedString = cRx("/^[#""'\[](.*)([""'#\]])$/") '0: String ohne Delemiter, 1: End-Delemiter: '," oder ]
'    If rxDelemitedString.Test(iString) Then
'        Dim sm As Object: Set sm = rxDelemitedString.Execute(iString)(0).subMatches
'        cValue = Replace(sm(0), "\" & sm(1), sm(1))
'    End If
'    'String 1 zu 1 zurückgeben
'    cValue = iString
'End Function
'/**
' * Dies ist die Minimalversion von cValue (V1.1.0): http://wiki.yaslaw.info/dokuwiki/doku.php/vba/cast/cvalue
' * Der 2te Paramtersteuert das Null-Verhalten('nebd'):
' *     n: Der Text Null ohne Delemiter wird als Wert Null intepretiert:    "NULL" -> Null
' *     e: Ein leerer String wird als Null intepretiert,                    "" -> Null
' *     b: Boolean-Text wird als Boolean intepretiert                       "True" -> True (Boolean)
' *     d: Bei Delemited Strings den Delemiter nicht entfernen. ' oder " gelten als Delemiter: "'Hans'" -> Hans
' */
Public Function cV(ByVal iValue As Variant, Optional ByVal iFlags As String) As Variant
    On Error Resume Next: If IsNull(iValue) Then cV = Null: Exit Function
    Static rxDa As Object, rxDs As Object: Dim sm As Object, str As String, flg As String:  str = CStr(iValue): flg = UCase(iFlags)
    If UCase(str) = "NULL" And InStr(flg, "N") Then cV = Null: Exit Function
    If iValue = Empty And CBool(InStr(flg, "E")) Then cV = Null: Exit Function
    cV = CByte(str):    If cV = str Then Exit Function
    cV = CInt(str):     If cV = str Then Exit Function
    cV = CLng(str):     If cV = str Then Exit Function
    cV = CDbl(str):     If cV = str Then Exit Function
    cV = CDec(str):     If cV = str Then Exit Function
    If IsDate(str) Then cV = CDate(str): Exit Function
    Err.Clear: If InStr(flg, "B") Then cV = CBool(str):   If Err.Number = 0 Then Exit Function
    If rxDa Is Nothing Then Set rxDa = CreateObject("VBScript.RegExp"): rxDa.pattern = "^#(.*)#$"
    If rxDa.test(str) Then cV = CDate(rxDa.execute(str)(0).subMatches(0)):  Exit Function
    If InStr(flg, "D") > 0 Then cV = iValue: Exit Function
    If rxDs Is Nothing Then Set rxDs = CreateObject("VBScript.RegExp"): rxDs.pattern = "^[#""'\[](.*)([""'#\]])$"
    If rxDs.test(str) Then Set sm = rxDs.execute(str)(0).subMatches: cV = replace(sm(0), "\" & sm(1), sm(1)):  Exit Function
    cV = iValue
End Function
 
'/**
' * Dies ist die Minimalversion von cRegExp
' * http://wiki.yaslaw.info/dokuwiki/doku.php/vba/cast/cregexp#abgespeckte_version
' * mögliche Delemiter: @&!/~#=\|
' * mögliche Modifiers: g (Global), i (IgnoreCode, m (Mulitline)
' *
' * @example    myRx = cRx("/([a]{2,})/i") 'Finde alle folgen von a. Flag:IgnoreCase
' * @version    2.1.0 (01.12.2014)
' * @param      String      Pattern mit Delimiter und Modifier analog zu PHP
' * @return     Object      RegExp-Object
' */
Private Function cRx(ByVal iPattern As String) As Object
    Static rxP As Object:       Set cRx = CreateObject("VBScript.RegExp")
    If rxP Is Nothing Then:     Set rxP = CreateObject("VBScript.RegExp"): rxP.pattern = "^([@&!/~#=\|])?(.*)\1(?:([Ii])|([Gg])|([Mm]))*$"
    Dim sm As Object:           Set sm = rxP.execute(iPattern)(0).subMatches
    cRx.pattern = sm(1):        cRx.IgnoreCase = Not isEmpty(sm(2)):       cRx.Global = Not isEmpty(sm(3)):     cRx.Multiline = Not isEmpty(sm(4))
End Function
 
'/**
' * Copyright mpl by ERB software | http://wiki.yaslaw.info
' *
' * Wandelt ein Unicode in ein Charakter
' * @example: unicode2char("\u20AC") -> '\€'
' * @param  String      Unicode
' * @return String      Char
' */
Private Function unicode2Char(ByVal iUnicode As String) As String
    unicode2Char = ChrW(replace(iUnicode, "\u", "&h"))
End Function
 
'/**
' * Copyright mpl by ERB software | http://wiki.yaslaw.info
' *
' * Wandelt ein Charakter in ein Unicode
' * @example: char2unicode("€") -> '\u20AC'
' * @param  String(1)   Charakter, der gewandelt werden soll
' * @return String      Unicode
' */
Private Function char2unicode(ByVal iChar As String) As String
    char2unicode = Hex(AscW(iChar)) 'Hex-Wert ermitteln
    char2unicode = "\u" & String(4 - Len(char2unicode), "0") & char2unicode
End Function
 
'/**
' * Copyright mpl by ERB software | http://wiki.yaslaw.info
' *
' * Ersetzt ein pestimmte Position in einem String
' * @param  String      Heystack
' * @param  String      Ersetzungsstring
' * @param  Integer     Position im String
' * @param  Integer     Länge des zu ersetzenden Strings
' */
Private Function replaceIndex(ByVal iExpression As Variant, ByVal iReplace As Variant, ByVal iIndex As Variant, Optional ByVal iLength As Integer = 1) As String
    replaceIndex = Left(iExpression, iIndex) & iReplace & Mid(iExpression, iIndex + iLength + 1)
End Function
 
'/**
' * Wandelt alle Unicodes in einem String in das eigentliche Zeichen zurück
' * @param  String
' * @return String
' */
Private Function unicodeDecode(ByVal iString) As String
    unicodeDecode = iString
    Static rx As Object
    If rx Is Nothing Then Set rx = cRx("/\\u[0-9A-F]{4}/i")
    Do While rx.test(unicodeDecode)
        unicodeDecode = rx.replace(unicodeDecode, unicode2Char(rx.execute(unicodeDecode)(0)))
    Loop
End Function
 

Discussion

Enter your comment. Wiki syntax is allowed:
If you can't read the letters on the image, download this .wav file to get them read to you.
 
vba/access/functions/persist.txt · Last modified: 24.11.2015 12:27:26 by yaslaw