ModValidate.vb 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. '提供不同的输入验证方法,名称以 Validate 开头
  2. ''' <summary>
  3. ''' 输入验证规则基类。要查看所有的输入验证规则,可在输入 Validate 后查看自动补全。
  4. ''' </summary>
  5. Public MustInherit Class Validate
  6. ''' <summary>
  7. ''' 验证某字符串是否符合验证要求。若符合,返回空字符串;若不符合,返回错误原因。
  8. ''' </summary>
  9. Public MustOverride Function Validate(Str As String) As String
  10. End Class
  11. ''' <summary>
  12. ''' 若为空则直接通过检查。
  13. ''' </summary>
  14. Public Class ValidateNullable
  15. Inherits Validate
  16. Public Sub New()
  17. End Sub
  18. Public Overrides Function Validate(Str As String) As String
  19. If IsNothing(Str) OrElse String.IsNullOrEmpty(Str) Then Return Nothing
  20. Return ""
  21. End Function
  22. End Class
  23. ''' <summary>
  24. ''' 不能为 Nothing 或空字符串(不包括全空格检查)。
  25. ''' </summary>
  26. Public Class ValidateNullOrEmpty
  27. Inherits Validate
  28. Public Sub New()
  29. End Sub
  30. Public Overrides Function Validate(Str As String) As String
  31. If IsNothing(Str) OrElse String.IsNullOrEmpty(Str) Then Return "输入内容不能为空!"
  32. Return ""
  33. End Function
  34. End Class
  35. ''' <summary>
  36. ''' 不能为 Nothing 或空字符串(包括全空格检查)。
  37. ''' </summary>
  38. Public Class ValidateNullOrWhiteSpace
  39. Inherits Validate
  40. Public Sub New()
  41. End Sub
  42. Public Overrides Function Validate(Str As String) As String
  43. If IsNothing(Str) OrElse String.IsNullOrWhiteSpace(Str) Then Return "输入内容不能为空!"
  44. Return ""
  45. End Function
  46. End Class
  47. ''' <summary>
  48. ''' 必须满足正则表达式。
  49. ''' </summary>
  50. Public Class ValidateRegex
  51. Inherits Validate
  52. Public Property Regex As String
  53. Public Property ErrorDescription As String = "正则检查失败!"
  54. Public Sub New()
  55. End Sub '用于 XAML 初始化
  56. Public Sub New(Regex As String, Optional ErrorDescription As String = "正则检查失败!")
  57. Me.Regex = Regex
  58. Me.ErrorDescription = ErrorDescription
  59. End Sub
  60. Public Overrides Function Validate(Str As String) As String
  61. If Not RegexCheck(Str, Regex) Then Return ErrorDescription
  62. Return ""
  63. End Function
  64. End Class
  65. ''' <summary>
  66. ''' 必须是一个完整网址。
  67. ''' </summary>
  68. Public Class ValidateHttp
  69. Inherits Validate
  70. Public Sub New()
  71. End Sub '用于 XAML 初始化
  72. Public Overrides Function Validate(Str As String) As String
  73. If Str.EndsWithF("/") Then Str = Str.Substring(0, Str.Length - 1)
  74. If Not RegexCheck(Str, "^(http[s]?)\://") Then Return "输入的网址无效!"
  75. Return ""
  76. End Function
  77. End Class
  78. ''' <summary>
  79. ''' 必须为整数。
  80. ''' </summary>
  81. Public Class ValidateInteger
  82. Inherits Validate
  83. Public Property Min As Integer
  84. Public Property Max As Integer = Integer.MaxValue
  85. Public Sub New()
  86. End Sub '用于 XAML 初始化
  87. Public Sub New(Min As Integer, Max As Integer)
  88. Me.Min = Min
  89. Me.Max = Max
  90. End Sub
  91. Public Overrides Function Validate(Str As String) As String
  92. If Str.Length > 9 Then Return "请输入一个大小合理的数字!"
  93. Dim Valed As Integer = Val(Str)
  94. If Valed.ToString <> Str Then Return "请输入一个整数!"
  95. If Val(Str) > Max Then Return "不可超过 " & Max & "!"
  96. If Val(Str) < Min Then Return "不可低于 " & Min & "!"
  97. Return ""
  98. End Function
  99. End Class
  100. ''' <summary>
  101. ''' 长度限制。
  102. ''' </summary>
  103. Public Class ValidateLength
  104. Inherits Validate
  105. Public Property Min As Integer = 0
  106. Public Property Max As Integer = Integer.MaxValue
  107. Public Sub New()
  108. End Sub '用于 XAML 初始化
  109. Public Sub New(Min As Integer, Optional Max As Integer = Integer.MaxValue)
  110. Me.Min = Min
  111. Me.Max = Max
  112. End Sub
  113. Public Overrides Function Validate(Str As String) As String
  114. If Len(Str) <> Max AndAlso Max = Min Then Return "长度必须为 " & Max & " 个字符!"
  115. If Len(Str) > Max Then Return "长度最长为 " & Max & " 个字符!"
  116. If Len(Str) < Min Then Return "长度至少需 " & Min & " 个字符!"
  117. Return ""
  118. End Function
  119. End Class
  120. ''' <summary>
  121. ''' 不能包含某些特定字符串。忽略大小写。
  122. ''' </summary>
  123. Public Class ValidateExcept
  124. Inherits Validate
  125. Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
  126. Public Property ErrorMessage As String
  127. Public Sub New()
  128. ErrorMessage = "输入内容不能包含 %!"
  129. End Sub '用于 XAML 初始化
  130. Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能包含 %!")
  131. Me.Excepts = Excepts
  132. Me.ErrorMessage = ErrorMessage
  133. End Sub
  134. Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能包含 %!")
  135. Me.Excepts = New ObjectModel.Collection(Of String)
  136. Me.ErrorMessage = ErrorMessage
  137. For Each Data As String In Excepts
  138. Me.Excepts.Add(Data)
  139. Next
  140. End Sub
  141. Public Overrides Function Validate(Str As String) As String
  142. For Each Ch As String In Excepts
  143. If Str.IndexOfF(Ch, True) >= 0 Then
  144. If IsNothing(ErrorMessage) Then ErrorMessage = ""
  145. Return ErrorMessage.Replace("%", Ch)
  146. End If
  147. Next
  148. Return ""
  149. End Function
  150. End Class
  151. ''' <summary>
  152. ''' 不能与某些特定字符串相同。
  153. ''' </summary>
  154. Public Class ValidateExceptSame
  155. Inherits Validate
  156. Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
  157. Public Property ErrorMessage As String
  158. Public Property IgnoreCase As Boolean = False
  159. Public Sub New()
  160. End Sub
  161. Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能为 %!", Optional IgnoreCase As Boolean = False)
  162. Me.Excepts = Excepts
  163. Me.ErrorMessage = ErrorMessage
  164. Me.IgnoreCase = IgnoreCase
  165. End Sub
  166. Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能为 %!", Optional IgnoreCase As Boolean = False)
  167. Me.Excepts = New ObjectModel.Collection(Of String)
  168. For Each Data As String In Excepts
  169. Me.Excepts.Add(Data)
  170. Next
  171. Me.ErrorMessage = ErrorMessage
  172. Me.IgnoreCase = IgnoreCase
  173. End Sub
  174. Public Overrides Function Validate(Str As String) As String
  175. If Str Is Nothing Then Return ErrorMessage.Replace("%", "null")
  176. For Each Ch As String In Excepts
  177. If IgnoreCase Then
  178. If Str.ToLower = Ch.ToLower Then Return ErrorMessage.Replace("%", Ch)
  179. Else
  180. If Str.Equals(Ch) Then Return ErrorMessage.Replace("%", Ch) '使用 = 不确定是否会忽略大小写
  181. End If
  182. Next
  183. Return ""
  184. End Function
  185. End Class
  186. ''' <summary>
  187. ''' 对文件夹名的粗略的特化检测。
  188. ''' </summary>
  189. Public Class ValidateFolderName
  190. Inherits Validate
  191. Public Property Path As String
  192. Public Property UseMinecraftCharCheck As Boolean = True
  193. Public Property IgnoreCase As Boolean = True
  194. Private ReadOnly PathIgnore As IEnumerable(Of DirectoryInfo)
  195. Public Sub New()
  196. End Sub
  197. Public Sub New(Path As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
  198. Me.Path = Path
  199. Me.IgnoreCase = IgnoreCase
  200. Me.UseMinecraftCharCheck = UseMinecraftCharCheck
  201. On Error Resume Next
  202. PathIgnore = New DirectoryInfo(Path).EnumerateDirectories
  203. End Sub
  204. Public Overrides Function Validate(Str As String) As String
  205. Try
  206. '检查是否为空
  207. Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
  208. If Not LengthCheck = "" Then Return LengthCheck
  209. '检查空格
  210. If Str.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
  211. If Str.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
  212. '检查长度
  213. LengthCheck = New ValidateLength(1, 100).Validate(Str)
  214. If Not LengthCheck = "" Then Return LengthCheck
  215. '检查尾部小数点
  216. If Str.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
  217. '检查特殊字符
  218. Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件夹名不可包含 % 字符!").Validate(Str)
  219. If Not CharactCheck = "" Then Return CharactCheck
  220. '检查特殊字符串
  221. Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!", True).Validate(Str)
  222. If Not InvalidStrCheck = "" Then Return InvalidStrCheck
  223. '检查文件夹重名
  224. Dim Arr As New List(Of String)
  225. If PathIgnore IsNot Nothing Then
  226. For Each Folder As DirectoryInfo In PathIgnore
  227. Arr.Add(Folder.Name)
  228. Next
  229. End If
  230. Dim SameNameCheck = New ValidateExceptSame(Arr, "不可与现有文件夹重名!", IgnoreCase).Validate(Str)
  231. If Not SameNameCheck = "" Then Return SameNameCheck
  232. Return ""
  233. Catch ex As Exception
  234. Log(ex, "检查文件夹名出错")
  235. Return "错误:" & ex.Message
  236. End Try
  237. End Function
  238. End Class
  239. ''' <summary>
  240. ''' 对文件名的粗略的特化检测。
  241. ''' </summary>
  242. Public Class ValidateFileName
  243. Inherits Validate
  244. Public Property Name As String
  245. Public Property UseMinecraftCharCheck As Boolean = True
  246. Public Property IgnoreCase As Boolean = True
  247. Public Property ParentFolder As String = Nothing
  248. Public Property RequireParentFolderExists = True
  249. Public Property AllowNull As Boolean = False
  250. Public Sub New()
  251. End Sub
  252. Public Sub New(Name As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
  253. Me.Name = Name
  254. Me.IgnoreCase = IgnoreCase
  255. Me.UseMinecraftCharCheck = UseMinecraftCharCheck
  256. End Sub
  257. Public Overrides Function Validate(Str As String) As String
  258. Try
  259. If Not AllowNull Then
  260. '检查是否为空
  261. Dim NullCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
  262. If Not NullCheck = "" Then Return NullCheck
  263. End If
  264. '检查空格
  265. If Str.StartsWithF(" ") Then Return "文件名不能以空格开头!"
  266. If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
  267. '检查长度
  268. Dim LengthCheck = New ValidateLength(If(AllowNull, 0, 1), 253).Validate(Str & If(ParentFolder, ""))
  269. If Not LengthCheck = "" Then Return LengthCheck
  270. '检查尾部小数点
  271. If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
  272. '检查特殊字符
  273. Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件名不可包含 % 字符!").Validate(Str)
  274. If Not CharactCheck = "" Then Return CharactCheck
  275. '检查特殊字符串
  276. Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件名不可为 %!", True).Validate(Str)
  277. If Not InvalidStrCheck = "" Then Return InvalidStrCheck
  278. '检查文件重名
  279. If ParentFolder IsNot Nothing Then
  280. Dim DirInfo As New DirectoryInfo(ParentFolder)
  281. If DirInfo.Exists Then
  282. Dim SameNameCheck = New ValidateExceptSame(DirInfo.EnumerateFiles("*").Select(Function(f) f.Name),
  283. "不可与现有文件重名!", IgnoreCase).Validate(Str)
  284. If Not SameNameCheck = "" Then Return SameNameCheck
  285. Else
  286. If RequireParentFolderExists Then Return $"父文件夹不存在:{ParentFolder}"
  287. End If
  288. End If
  289. Return ""
  290. Catch ex As Exception
  291. Log(ex, "检查文件名出错")
  292. Return "错误:" & ex.Message
  293. End Try
  294. End Function
  295. End Class
  296. ''' <summary>
  297. ''' 要求输入一个可用的文件夹路径。
  298. ''' </summary>
  299. Public Class ValidateFolderPath
  300. Inherits Validate
  301. Public Property UseMinecraftCharCheck As Boolean = True
  302. Public Sub New()
  303. End Sub
  304. Public Sub New(UseMinecraftCharCheck As Boolean)
  305. Me.UseMinecraftCharCheck = UseMinecraftCharCheck
  306. End Sub
  307. Public Overrides Function Validate(Str As String) As String
  308. '去除尾部斜线,统一为 \
  309. Str = Str.Replace("/", "\")
  310. If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
  311. '检查是否为空
  312. Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
  313. If Not LengthCheck = "" Then Return LengthCheck
  314. '检查长度
  315. LengthCheck = New ValidateLength(1, 254).Validate(Str)
  316. If Not LengthCheck = "" Then Return LengthCheck
  317. '检查开头
  318. If Str.StartsWithF("\\Mac\") Then GoTo Fin
  319. For Each Drive As DriveInfo In My.Computer.FileSystem.Drives
  320. If Str.ToUpper = Drive.Name Then Return ""
  321. If Str.StartsWithF(Drive.Name, True) Then GoTo Fin
  322. Next
  323. Return "文件夹路径头存在错误!"
  324. Fin:
  325. '对首层以外的路径检查
  326. For i = If(Str.StartsWithF("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
  327. Dim SubStr As String = Str.Split("\")(i)
  328. '检查是否为空
  329. Dim SubLengthCheck As String = New ValidateNullOrWhiteSpace().Validate(SubStr)
  330. If Not SubLengthCheck = "" Then Return "文件夹路径存在错误!"
  331. '检查特殊字符
  332. Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "路径中存在无效字符!").Validate(SubStr)
  333. If Not CharactCheck = "" Then Return CharactCheck
  334. '检查头部空格
  335. If SubStr.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
  336. If SubStr.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
  337. '检查尾部小数点
  338. If SubStr.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
  339. '检查特殊字符串
  340. Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr)
  341. If Not InvalidStrCheck = "" Then Return InvalidStrCheck
  342. Next
  343. Return ""
  344. End Function
  345. End Class