实现代码如下:
#Include "windows.bi"
#Include "crt.bi"
#include "vbcompat.bi"
/'
xywh Base Struct Memory Manage [基本结构化内存管理器]
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬──┐
│01│02│03│04│05│06│07│08│09│10│11│12│ .. │
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┘
'/
Type xBsmm
' 管理器内存指针
StructMemory As Any Ptr
' 成员占用内存长度
StructLenght As UInteger
' 管理器中存在多少成员
StructCount As UInteger
' 已经申请的结构数量
AllocCount As UInteger
' 预分配内存步长
AllocStep As UInteger
' 构造函数
Declare Constructor(iItemLenght As UInteger, PreassignStep As UInteger = 32, PreassignLenght As UInteger = 0)
' 析构函数
Declare Destructor()
' 添加成员
Declare Function InsertStruct(iPos As UInteger, iCount As UInteger = 1) As UInteger
Declare Function AppendStruct(iCount As UInteger = 1) As UInteger
' 删除成员
Declare Function DeleteStruct(iPos As UInteger, iCount As UInteger = 1) As Integer
' 移动成员
Declare Function SwapStruct(iPosA As UInteger, iPosB As UInteger) As Integer
' 获取成员指针
Declare Function GetPtrStruct(iPos As UInteger) As Any Ptr
' 分配内存
Declare Function CallocMemory(iCount As UInteger) As Integer
' 重置(释放资源)
Declare Sub ReInitManage()
End Type
' 构造函数
Constructor xBsmm(iItemLenght As UInteger, PreassignStep As UInteger = 32, PreassignLenght As UInteger = 0)
StructLenght = iItemLenght
AllocStep = PreassignStep
If PreassignLenght Then
CallocMemory(PreassignLenght)
EndIf
End Constructor
' 析构函数
Destructor xBsmm()
ReInitManage()
End Destructor
' 添加成员 [成功返回idx,失败返回0]
Function xBsmm.InsertStruct(iPos As UInteger, iCount As UInteger = 1) As UInteger
' 不能添加0个成员
If iCount = 0 Then
Return 0
EndIf
' 分配内存
If StructCount + iCount > AllocCount Then
If CallocMemory(StructCount + iCount + AllocStep) = 0 Then
Return 0
EndIf
EndIf
If iPos < StructCount Then
' 插入
memmove(StructMemory + ((iPos + iCount) * StructLenght), StructMemory + (iPos * StructLenght), (StructCount - iPos) * StructLenght)
'Function = StructMemory + (iPos * StructLenght)
Function = iPos + 1
StructCount += iCount
Else
' 添加
'Function = StructMemory + (StructCount * StructLenght)
Function = StructCount + 1
StructCount += iCount
EndIf
End Function
Function xBsmm.AppendStruct(iCount As UInteger = 1) As UInteger
Return InsertStruct(StructCount, iCount)
End Function
' 删除成员
Function xBsmm.DeleteStruct(iPos As UInteger, iCount As UInteger = 1) As Integer
' 不能删除0个成员
If iCount Then
' 范围检查
If iPos Then
iPos -= 1
If iPos < StructCount Then
If iPos + iCount < StructCount Then
' 中段删除
memmove(StructMemory + (iPos * StructLenght), StructMemory + ((iPos + iCount) * StructLenght), (StructCount - (iPos + iCount)) * StructLenght)
StructCount -= iCount
Else
' 末尾删除
StructCount = iPos
EndIf
Return -1
EndIf
EndIf
EndIf
End Function
' 移动成员
Function xBsmm.SwapStruct(iPosA As UInteger, iPosB As UInteger) As Integer
' 范围检查
If (iPosA <> 0) And (iPosB <> 0) Then
iPosA -= 1
iPosB -= 1
If (iPosA < StructCount) And (iPosB < StructCount) Then
If iPosA <> iPosB Then
' 交换数据
Dim StuA As Any Ptr = malloc(StructLenght)
memmove(StuA, StructMemory + (iPosA * StructLenght), StructLenght)
memmove(StructMemory + (iPosA * StructLenght), StructMemory + (iPosB * StructLenght), StructLenght)
memmove(StructMemory + (iPosB * StructLenght), StuA, StructLenght)
Return -1
Else
' 位置相同,不需要交换
Return -1
EndIf
EndIf
EndIf
End Function
' 获取成员指针
Function xBsmm.GetPtrStruct(iPos As UInteger) As Any Ptr
If iPos Then
iPos -= 1
If iPos < StructCount Then
Return StructMemory + (iPos * StructLenght)
EndIf
EndIf
End Function
' 分配内存
Function xBsmm.CallocMemory(iCount As UInteger) As Integer
If iCount > AllocCount Then
' 增量
Dim NewMem As Any Ptr = realloc(StructMemory, iCount * StructLenght)
If NewMem Then
AllocCount = iCount
StructMemory = NewMem
Return -1
EndIf
ElseIf iCount < AllocCount Then
' 裁剪
Dim NewMem As Any Ptr = realloc(StructMemory, iCount * StructLenght)
If NewMem Then
AllocCount = iCount
StructMemory = NewMem
If iCount <= StructCount Then
' 需要裁剪数据
StructCount = iCount
EndIf
Return -1
EndIf
ElseIf iCount = 0 Then
' 清空
ReInitManage()
Else
' 不变
Return -1
EndIf
Return 0
End Function
' 重置(释放资源)
Sub xBsmm.ReInitManage()
If StructMemory Then
free(StructMemory)
StructMemory = NULL
EndIf
StructCount = 0
AllocCount = 0
End Sub
#Define CDate_Format_Error(s) Print(s):Cells.ReInitManage():Return
#Define CDate_Error(s) Print(s):Delete pObjFormat:Return 0
' CDate 函数缺省的格式字符串
Dim Shared s_CDate_DefaultFotmat As ZString * 32 = "yyyy.mm.dd.hh.mm.ss"
' 数据格式单元结构体
Type CDate_Format_Cell
' 数据格式单元类型 [ y=1 m=2 d=3 h=4 n=5 s=6 +=7 *=8 space=9 ?=10 str=0 ]
Dim iType As Integer
' 数据单元匹配的字符串
Dim sText As ZString * 60
End Type
' 数据格式解析类
Type CDate_Format
' 要处理的格式数量
Dim Cells As xBsmm = SizeOf(CDate_Format_Cell)
' 构造函数
Declare Constructor(sFormat As ZString Ptr)
' 析构函数
Declare Destructor()
End Type
' 构造函数 [处理格式化字符串]
Constructor CDate_Format(sFormat As ZString Ptr)
If sFormat = NULL Then
sFormat = @s_CDate_DefaultFotmat
EndIf
Dim iSize As Integer = strlen(sFormat)
Dim sTempAddr As ZString Ptr = sFormat
Dim iTempSize As Integer = 0
Dim iType As Integer = 0 ' 见 : 数据格式单元类型
Dim bHour As Integer = FALSE
' 自动添加一个 * 数据格式单元
Dim pCell As CDate_Format_Cell Ptr = Cells.GetPtrStruct(Cells.AppendStruct())
If pCell Then
pCell->iType = 8
pCell->sText = ""
Else
' 申请内存出错
CDate_Format_Error("malloc error")
EndIf
' 开始解析
For i As Integer = 0 To iSize - 1
iTempSize += 1
' 判断当前解析类型
Dim iCurType As Integer = 0
If Cast(UByte Ptr, sFormat)[i] = 121 Then iCurType = 1
If Cast(UByte Ptr, sFormat)[i] = 109 Then iCurType = 2
If Cast(UByte Ptr, sFormat)[i] = 100 Then iCurType = 3
If Cast(UByte Ptr, sFormat)[i] = 104 Then iCurType = 4
If Cast(UByte Ptr, sFormat)[i] = 110 Then iCurType = 5
If Cast(UByte Ptr, sFormat)[i] = 115 Then iCurType = 6
If Cast(UByte Ptr, sFormat)[i] = 46 Then iCurType = 7
If Cast(UByte Ptr, sFormat)[i] = 42 Then iCurType = 8
If Cast(UByte Ptr, sFormat)[i] = 32 Then iCurType = 9
If Cast(UByte Ptr, sFormat)[i] = 63 Then iCurType = 10
If iCurType Then
' 跳过重复的字符 [y、m、d、h、n、s]
If (iType = iCurType) AndAlso (iCurType < 10) Then
sTempAddr = @sFormat[i+1]
iTempSize = 0
Continue For
EndIf
' 先记录字符串匹配单元
If iTempSize > 1 Then
Dim pCell As CDate_Format_Cell Ptr = Cells.GetPtrStruct(Cells.AppendStruct())
If pCell Then
pCell->iType = 0
strncpy(@pCell->sText, sTempAddr, iTempSize-1)
pCell->sText[iTempSize-1] = 0
Else
' 申请内存出错
CDate_Format_Error("malloc error")
EndIf
End If
' 记录特殊匹配单元
Dim pCell As CDate_Format_Cell Ptr = Cells.GetPtrStruct(Cells.AppendStruct())
If pCell Then
pCell->iType = IIf(bHour AndAlso (iCurType = 2), 5, iCurType)
pCell->sText = ""
Else
' 申请内存出错
CDate_Format_Error("malloc error")
EndIf
sTempAddr = @sFormat[i+1]
iTempSize = 0
iType = iCurType
' 为 m 做特殊处理 [ 跟在 h 后面的时候算作 n ]
If iType < 7 Then bHour = IIf(iType = 4, TRUE, FALSE)
Else
' 其他情况
iType = 0
End If
' 检查缓冲区是否溢出 [固定字符串匹配最多支持59个字符]
If iTempSize >= 60 Then
CDate_Format_Error("buffer size max 60 byte")
EndIf
'Print Cast(UByte Ptr, sFormat)[i], sFormat[i]
Next
End Constructor
' 析构函数
Destructor CDate_Format()
Cells.ReInitManage()
End Destructor
Function CDate_CheckNumber(sText As UByte Ptr, iMin As Integer, iMax As Integer) As Integer
Dim iSize As Integer
' 判断最小长度是否合格
For i As Integer = 0 To iMin - 1
If isdigit(sText[i]) = 0 Then
Return 0
EndIf
Next
iSize = iMin
' 判断数字长度
For i As Integer = iMin To iMax - 1
If isdigit(sText[i]) Then
iSize = i + 1
EndIf
Next
' 判断最大长度是否合格
If (iSize = iMax) AndAlso isdigit(sText[iMax]) Then
Return 0
EndIf
Return iSize
End Function
Function CDate(sText As ZString Ptr, sFormat As ZString Ptr = NULL) As Double
Dim pObjFormat As CDate_Format ptr = New CDate_Format(sFormat)
If pObjFormat AndAlso pObjFormat->Cells.StructCount Then
Dim sTempAddr As UByte Ptr = sText
Dim sNumber As ZString * 16 = ""
Dim As Integer y, m, d, h, n, s
For i As Integer = 1 To pObjFormat->Cells.StructCount
Dim pCell As CDate_Format_Cell Ptr = pObjFormat->Cells.GetPtrStruct(i)
'Print pCell->iType, pCell->sText
Select Case pCell->iType
Case 0
' 字符串完全匹配
Dim iSize As Integer = strlen(@pCell->sText)
If strncmp(@pCell->sText, sTempAddr, iSize) = 0 Then
sTempAddr += iSize
Else
CDate_Error("StrComp Fail : " & pCell->sText)
EndIf
Case 1
' 匹配年
Dim iSize As Integer = CDate_CheckNumber(sTempAddr, 4, 4)
If iSize > 0 Then
memcpy(@sNumber, sTempAddr, iSize)
sNumber[iSize] = 0
y = atoi(@sNumber)
sTempAddr += iSize
Else
CDate_Error("Year Fail")
EndIf
Case 2
' 匹配月
Dim iSize As Integer = CDate_CheckNumber(sTempAddr, 1, 2)
If iSize > 0 Then
memcpy(@sNumber, sTempAddr, iSize)
sNumber[iSize] = 0
m = atoi(@sNumber)
sTempAddr += iSize
Else
CDate_Error("Month Fail")
EndIf
Case 3
' 匹配日期
Dim iSize As Integer = CDate_CheckNumber(sTempAddr, 1, 2)
If iSize > 0 Then
memcpy(@sNumber, sTempAddr, iSize)
sNumber[iSize] = 0
d = atoi(@sNumber)
sTempAddr += iSize
Else
CDate_Error("Day Fail")
EndIf
Case 4
' 匹配时
Dim iSize As Integer = CDate_CheckNumber(sTempAddr, 1, 2)
If iSize > 0 Then
memcpy(@sNumber, sTempAddr, iSize)
sNumber[iSize] = 0
h = atoi(@sNumber)
sTempAddr += iSize
Else
CDate_Error("Hour Fail")
EndIf
Case 5
' 匹配分
Dim iSize As Integer = CDate_CheckNumber(sTempAddr, 1, 2)
If iSize > 0 Then
memcpy(@sNumber, sTempAddr, iSize)
sNumber[iSize] = 0
n = atoi(@sNumber)
sTempAddr += iSize
Else
CDate_Error("Minute Fail")
EndIf
Case 6
' 匹配秒
Dim iSize As Integer = CDate_CheckNumber(sTempAddr, 1, 2)
If iSize > 0 Then
memcpy(@sNumber, sTempAddr, iSize)
sNumber[iSize] = 0
s = atoi(@sNumber)
sTempAddr += iSize
Else
CDate_Error("Second Fail")
EndIf
Case 7
' 匹配任意字符 [至少一个]
If isdigit(sTempAddr[0]) Then
Delete pObjFormat
Return 0
EndIf
Dim iOffset As Integer = 1
Do
If isdigit(sTempAddr[iOffset]) Then
Exit Do
EndIf
iOffset += 1
Loop
sTempAddr += iOffset
Case 8
' 匹配任意字符
Dim iOffset As Integer = 0
Do
If isdigit(sTempAddr[iOffset]) Then
Exit Do
EndIf
iOffset += 1
Loop
sTempAddr += iOffset
Case 9
' 匹配任意空白字符 [Space、Tab]
Dim iOffset As Integer = 0
Do
If (sTempAddr[iOffset] <> 32) AndAlso (sTempAddr[iOffset] <> 9) Then
Exit Do
EndIf
iOffset += 1
Loop
sTempAddr += iOffset
Case 10
' 匹配任意字符一个
If sTempAddr[0] And 128 Then
sTempAddr += 2
Else
sTempAddr += 1
EndIf
End Select
Next
Delete pObjFormat
Return DateSerial(y, m, d) + TimeSerial(h, n, s)
Else
' 函数执行失败返回 0
Return 0
EndIf
End Function
/'
格式化字符串说明:
y 解析年份,必须 4 位数字
m 解析月份,1 - 2 位数字,当 m 紧跟在 h 后面时,按照分钟解析
d 解析日期,1 - 2 位数字
h 解析小时,1 - 2 位数字
n 解析分钟,1 - 2 位数字
s 解析秒,1 - 2 位数字
* 解析任意字符 0 次至无限次,直到遇到数字
. 解析任意字符 1 次至无限次,直到遇到数字
? 解析任意字符 1 次,中文字符也按照一个字符计算
Space 解析空白字符(Space、Tab) 0 次至无限次
其他字符将按照完全匹配解析
*备注 : 解析格式化字符串时,会自动在最前面生成一个 *
更新计划(已知问题):
* 和 . 两个符号根据之后匹配的内容自动匹配到特定位置(现在他们后面必须跟数字匹配)
添加对字符串 \0 结尾的处理(现在没有对 \0 结尾做处理,有缓冲区溢出风险)
'/
Dim DT As Double = CDate("当前时间为:2018年9月14日 8:30:12", "yyyy年mm月dd日 hh:mm:ss")
Print DT
Print Format(DT, "yyyy.mm.dd hh:mm:ss")
Print "----------------"
DT = CDate("当前时间为:2019年12月6日 12:5:6")
Print DT
Print Format(DT, "yyyy.mm.dd hh:mm:ss")
Sleep