nss: upgrade to release 3.73
[LibreOffice.git] / wizards / source / scriptforge / SF_String.xba
blob272a2d1cefa723dbf78aaf34793fd8151e5a6157
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
3 <script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_String" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
4 REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
5 REM === Full documentation is available on https://help.libreoffice.org/ ===
6 REM =======================================================================================================================
8 Option Compatible
9 Option Explicit
11 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
12 &apos;&apos;&apos; SF_String
13 &apos;&apos;&apos; =========
14 &apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.String&quot; service
15 &apos;&apos;&apos; Implemented as a usual Basic module
16 &apos;&apos;&apos; Focus on string manipulation, regular expressions, encodings and hashing algorithms
17 &apos;&apos;&apos; The first argument of almost every method is the string to consider
18 &apos;&apos;&apos; It is always passed by reference and left unchanged
19 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
20 &apos;&apos;&apos; Definitions
21 &apos;&apos;&apos; Line breaks: symbolic name(Ascii number)
22 &apos;&apos;&apos; LF(10), VT(12), CR(13), LF+CR, File separator(28), Group separator(29), Record separator(30),
23 &apos;&apos;&apos; Next Line(133), Line separator(8232), Paragraph separator(8233)
24 &apos;&apos;&apos; Whitespaces: symbolic name(Ascii number)
25 &apos;&apos;&apos; Space(32), HT(9), LF(10), VT(11), FF(12), CR(13), Next Line(133), No-break space(160),
26 &apos;&apos;&apos; Line separator(8232), Paragraph separator(8233)
27 &apos;&apos;&apos; A quoted string:
28 &apos;&apos;&apos; The quoting character must be the double quote (&quot;)
29 &apos;&apos;&apos; To preserve a quoting character inside the quoted substring, use (\) or (&quot;) as escape character
30 &apos;&apos;&apos; =&gt; [str\&quot;i&quot;&quot;ng] means [str&quot;i&quot;ng]
31 &apos;&apos;&apos; Escape sequences: symbolic name(Ascii number) = escape sequence
32 &apos;&apos;&apos; Line feed(10) = &quot;\n&quot;
33 &apos;&apos;&apos; Carriage return(13) = &quot;\r&quot;
34 &apos;&apos;&apos; Horizontal tab(9) = &quot;\t&quot;
35 &apos;&apos;&apos; Double the backslash to ignore the sequence, e.g. &quot;\\n&quot; means &quot;\n&quot; (not &quot;\&quot; &amp; Chr(10)).
36 &apos;&apos;&apos; Not printable characters:
37 &apos;&apos;&apos; Defined in the Unicode character database as “Other” or “Separator”
38 &apos;&apos;&apos; In particular, &quot;control&quot; characters (ascii code &lt;= 0x1F) are not printable
39 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
40 &apos;&apos;&apos; Some references:
41 &apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1i18n_1_1KCharacterType.html
42 &apos;&apos;&apos; com.sun.star.i18n.KCharacterType.###
43 &apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1i18n_1_1XCharacterClassification.html
44 &apos;&apos;&apos; com.sun.star.i18n.XCharacterClassification
46 REM ============================================================ MODULE CONSTANTS
48 &apos;&apos;&apos; Most expressions below are derived from https://www.regular-expressions.info/
50 Const REGEXALPHA = &quot;^[A-Za-z]+$&quot; &apos; Not used
51 Const REGEXALPHANUM = &quot;^[\w]+$&quot;
52 Const REGEXDATEDAY = &quot;(0[1-9]|[12][0-9]|3[01])&quot;
53 Const REGEXDATEMONTH = &quot;(0[1-9]|1[012])&quot;
54 Const REGEXDATEYEAR = &quot;(19|20)\d\d&quot;
55 Const REGEXTIMEHOUR = &quot;(0[1-9]|1[0-9]|2[0123])&quot;
56 Const REGEXTIMEMIN = &quot;([0-5][0-9])&quot;
57 Const REGEXTIMESEC = REGEXTIMEMIN
58 Const REGEXDIGITS = &quot;^[0-9]+$&quot;
59 Const REGEXEMAIL = &quot;^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$&quot;
60 Const REGEXFILELINUX = &quot;^[^&lt;&gt;:;,?&quot;&quot;*|\\]+$&quot;
61 Const REGEXFILEWIN = &quot;^([A-Z]|[a-z]:)?[^&lt;&gt;:;,?&quot;&quot;*|]+$&quot;
62 Const REGEXHEXA = &quot;^(0X|&amp;H)?[0-9A-F]+$&quot; &apos; Includes 0xFF and &amp;HFF
63 Const REGEXIPV4 = &quot;^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$&quot;
64 Const REGEXNUMBER = &quot;^[-+]?(([0-9]+)?\.)?[0-9]+([eE][-+]?[0-9]+)?$&quot;
65 Const REGEXURL = &quot;^(https?|ftp)://[^\s/$.?#].[^\s]*$&quot;
66 Const REGEXWHITESPACES = &quot;^[\s]+$&quot;
67 Const REGEXLTRIM = &quot;^[\s]+&quot;
68 Const REGEXRTRIM = &quot;[\s]+$&quot;
69 Const REGEXSPACES = &quot;[\s]+&quot;
71 &apos;&apos;&apos; Accented characters substitution: https://docs.google.com/spreadsheets/d/1pJKSueZK8RkAcJFQIiKpYUamWSC1u1xVQchK7Z7BIwc/edit#gid=0
72 &apos;&apos;&apos; (Many of them are in the list, but do not consider the list as closed vs. the Unicode database)
74 Const cstCHARSWITHACCENT = &quot;ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿŠšŸŽž&quot; _
75 &amp; &quot;ĂăĐđĨĩŨũƠơƯưẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹ₫&quot;
76 Const cstCHARSWITHOUTACCENT = &quot;AAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyySsYZz&quot; _
77 &amp; &quot;AaDdIiUuOoUuAaAaAaAaAaAaAaAaAaAaAaAaEeEeEeEeEeEeEeEeIiIiOoOoOoOoOoOoOoOoOoOoOoOoUuUuUuUuUuUuUuYyYyYyYyd&quot;
79 REM ===================================================== CONSTRUCTOR/DESTRUCTOR
81 REM -----------------------------------------------------------------------------
82 Public Function Dispose() As Variant
83 Set Dispose = Nothing
84 End Function &apos; ScriptForge.SF_String Explicit destructor
86 REM ================================================================== PROPERTIES
88 REM -----------------------------------------------------------------------------
89 Property Get CHARSWITHACCENT() As String
90 &apos;&apos;&apos; Latin accents
91 CHARSWITHACCENT = cstCHARSWITHACCENT
92 End Property &apos; ScriptForge.SF_String.CHARSWITHACCENT
94 REM -----------------------------------------------------------------------------
95 Property Get CHARSWITHOUTACCENT() As String
96 &apos;&apos;&apos; Latin accents
97 CHARSWITHOUTACCENT = cstCHARSWITHOUTACCENT
98 End Property &apos; ScriptForge.SF_String.CHARSWITHOUTACCENT
100 &apos;&apos;&apos; Symbolic constants for linebreaks
101 REM -----------------------------------------------------------------------------
102 Property Get sfCR() As Variant
103 &apos;&apos;&apos; Carriage return
104 sfCR = Chr(13)
105 End Property &apos; ScriptForge.SF_String.sfCR
107 REM -----------------------------------------------------------------------------
108 Property Get sfCRLF() As Variant
109 &apos;&apos;&apos; Carriage return
110 sfCRLF = Chr(13) &amp; Chr(10)
111 End Property &apos; ScriptForge.SF_String.sfCRLF
113 REM -----------------------------------------------------------------------------
114 Property Get sfLF() As Variant
115 &apos;&apos;&apos; Linefeed
116 sfLF = Chr(10)
117 End Property &apos; ScriptForge.SF_String.sfLF
119 REM -----------------------------------------------------------------------------
120 Property Get sfNEWLINE() As Variant
121 &apos;&apos;&apos; Linefeed or Carriage return + Linefeed
122 sfNEWLINE = Iif(GetGuiType() = 1, Chr(13), &quot;&quot;) &amp; Chr(10)
123 End Property &apos; ScriptForge.SF_String.sfNEWLINE
125 REM -----------------------------------------------------------------------------
126 Property Get sfTAB() As Variant
127 &apos;&apos;&apos; Horizontal tabulation
128 sfTAB = Chr(9)
129 End Property &apos; ScriptForge.SF_String.sfTAB
131 REM -----------------------------------------------------------------------------
132 Property Get ObjectType As String
133 &apos;&apos;&apos; Only to enable object representation
134 ObjectType = &quot;SF_String&quot;
135 End Property &apos; ScriptForge.SF_String.ObjectType
137 REM -----------------------------------------------------------------------------
138 Property Get ServiceName As String
139 &apos;&apos;&apos; Internal use
140 ServiceName = &quot;ScriptForge.String&quot;
141 End Property &apos; ScriptForge.SF_String.ServiceName
143 REM ============================================================== PUBLIC METHODS
145 REM -----------------------------------------------------------------------------
146 Public Function Capitalize(Optional ByRef InputStr As Variant) As String
147 &apos;&apos;&apos; Return the input string with the 1st character of each word in title case
148 &apos;&apos;&apos; Args:
149 &apos;&apos;&apos; InputStr: the input string
150 &apos;&apos;&apos; Returns:
151 &apos;&apos;&apos; The input string with the 1st character of each word in title case
152 &apos;&apos;&apos; Examples:
153 &apos;&apos;&apos; SF_String.Capitalize(&quot;this is a title for jean-pierre&quot;) returns &quot;This Is A Title For Jean-Pierre&quot;
155 Dim sCapital As String &apos; Return value
156 Dim lLength As Long &apos; Length of input string
157 Dim oLocale As Object &apos; com.sun.star.lang.Locale
158 Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
159 Const cstThisSub = &quot;String.Capitalize&quot;
160 Const cstSubArgs = &quot;InputStr&quot;
162 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
163 sCapital = &quot;&quot;
165 Check:
166 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
167 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
168 End If
170 Try:
171 lLength = Len(InputStr)
172 If lLength &gt; 0 Then
173 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
174 Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
175 sCapital = oChar.toTitle(InputStr, 0, lLength * 4, oLocale) &apos; length * 4 because length is expressed in bytes
176 End If
178 Finally:
179 Capitalize = sCapital
180 SF_Utils._ExitFunction(cstThisSub)
181 Exit Function
182 Catch:
183 GoTo Finally
184 End Function &apos; ScriptForge.SF_String.Capitalize
186 REM -----------------------------------------------------------------------------
187 Public Function Count(Optional ByRef InputStr As Variant _
188 , Optional ByVal Substring As Variant _
189 , Optional ByRef IsRegex As Variant _
190 , Optional ByVal CaseSensitive As Variant _
191 ) As Long
192 &apos;&apos;&apos; Counts the number of occurrences of a substring or a regular expression within a string
193 &apos;&apos;&apos; Args:
194 &apos;&apos;&apos; InputStr: the input stringto examine
195 &apos;&apos;&apos; Substring: the substring to identify
196 &apos;&apos;&apos; IsRegex: True if Substring is a regular expression (default = False)
197 &apos;&apos;&apos; CaseSensitive: default = False
198 &apos;&apos;&apos; Returns:
199 &apos;&apos;&apos; The number of occurrences as a Long
200 &apos;&apos;&apos; Examples:
201 &apos;&apos;&apos; SF_String.Count(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;\b[a-z]+\b&quot;, IsRegex := True, CaseSensitive := True)
202 &apos;&apos;&apos; returns 7 (the number of words in lower case)
203 &apos;&apos;&apos; SF_String.Count(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;or&quot;, CaseSensitive := False)
204 &apos;&apos;&apos; returns 2
207 Dim lOccurrences As Long &apos; Return value
208 Dim lStart As Long &apos; Start index of search
209 Dim sSubstring As String &apos; Substring to replace
210 Dim iCaseSensitive As Integer &apos; Integer alias for boolean CaseSensitive
211 Const cstThisSub = &quot;String.Count&quot;
212 Const cstSubArgs = &quot;InputStr, Substring, [IsRegex=False], [CaseSensitive=False]&quot;
214 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
215 lOccurrences = 0
217 Check:
218 If IsMissing(IsRegex) Or IsEmpty(IsRegex) Then IsRegex = False
219 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
220 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
221 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
222 If Not SF_Utils._Validate(Substring, &quot;Substring&quot;, V_STRING) Then GoTo Finally
223 If Not SF_Utils._Validate(IsRegex, &quot;IsRegex&quot;, V_BOOLEAN) Then GoTo Finally
224 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
225 End If
227 Try:
228 iCaseSensitive = Iif(CaseSensitive, 0, 1) &apos; 1 = False ;)
229 lStart = 1
231 Do While lStart &gt;= 1 And lStart &lt;= Len(InputStr)
232 Select Case IsRegex
233 Case False &apos; Use InStr
234 lStart = InStr(lStart, InputStr, Substring, iCaseSensitive)
235 If lStart = 0 Then Exit Do
236 lStart = lStart + Len(Substring)
237 Case True &apos; Use FindRegex
238 sSubstring = SF_String.FindRegex(InputStr, Substring, lStart, CaseSensitive)
239 If lStart = 0 Then Exit Do
240 lStart = lStart + Len(sSubstring)
241 End Select
242 lOccurrences = lOccurrences + 1
243 Loop
245 Finally:
246 Count = lOccurrences
247 SF_Utils._ExitFunction(cstThisSub)
248 Exit Function
249 Catch:
250 GoTo Finally
251 End Function &apos; ScriptForge.SF_String.Count
253 REM -----------------------------------------------------------------------------
254 Public Function EndsWith(Optional ByRef InputStr As Variant _
255 , Optional ByVal Substring As Variant _
256 , Optional ByVal CaseSensitive As Variant _
257 ) As Boolean
258 &apos;&apos;&apos; Returns True if the last characters of InputStr are identical to Substring
259 &apos;&apos;&apos; Args:
260 &apos;&apos;&apos; InputStr: the input string
261 &apos;&apos;&apos; Substring: the suffixing characters
262 &apos;&apos;&apos; CaseSensitive: default = False
263 &apos;&apos;&apos; Returns:
264 &apos;&apos;&apos; True if the comparison is satisfactory
265 &apos;&apos;&apos; False if either InputStr or Substring have a length = 0
266 &apos;&apos;&apos; False if Substr is longer than InputStr
267 &apos;&apos;&apos; Examples:
268 &apos;&apos;&apos; SF_String.EndsWith(&quot;abcdefg&quot;, &quot;EFG&quot;) returns True
269 &apos;&apos;&apos; SF_String.EndsWith(&quot;abcdefg&quot;, &quot;EFG&quot;, CaseSensitive := True) returns False
271 Dim bEndsWith As Boolean &apos; Return value
272 Dim lSub As Long &apos; Length of SUbstring
273 Const cstThisSub = &quot;String.EndsWith&quot;
274 Const cstSubArgs = &quot;InputStr, Substring, [CaseSensitive=False]&quot;
276 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
277 bEndsWith = False
279 Check:
280 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
281 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
282 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
283 If Not SF_Utils._Validate(Substring, &quot;Substring&quot;, V_STRING) Then GoTo Finally
284 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
285 End If
287 Try:
288 lSub = Len(Substring)
289 If Len(InputStr) &gt; 0 And lSub &gt; 0 And lSub &lt;= Len(InputStr) Then
290 bEndsWith = ( StrComp(Right(InputStr, lSub), Substring, Iif(CaseSensitive, 1, 0)) = 0 )
291 End If
293 Finally:
294 EndsWith = bEndsWith
295 SF_Utils._ExitFunction(cstThisSub)
296 Exit Function
297 Catch:
298 GoTo Finally
299 End Function &apos; ScriptForge.SF_String.EndsWith
301 REM -----------------------------------------------------------------------------
302 Public Function Escape(Optional ByRef InputStr As Variant) As String
303 &apos;&apos;&apos; Convert any hard line breaks or tabs by their escaped equivalent
304 &apos;&apos;&apos; Args:
305 &apos;&apos;&apos; InputStr: the input string
306 &apos;&apos;&apos; Returns:
307 &apos;&apos;&apos; The input string after replacement of &quot;\&quot;, Chr(10), Chr(13), Chr(9)characters
308 &apos;&apos;&apos; Examples:
309 &apos;&apos;&apos; SF_String.Escape(&quot;abc&quot; &amp; Chr(10) &amp; Chr(9) &amp; &quot;def\n&quot;) returns &quot;abc\n\tdef\\n&quot;
311 Dim sEscape As String &apos; Return value
312 Const cstThisSub = &quot;String.Escape&quot;
313 Const cstSubArgs = &quot;InputStr&quot;
315 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
316 sEscape = &quot;&quot;
318 Check:
319 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
320 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
321 End If
323 Try:
324 sEscape = SF_String.ReplaceStr( InputStr _
325 , Array(&quot;\&quot;, SF_String.sfLF, SF_String.sfCR, SF_String.sfTAB) _
326 , Array(&quot;\\&quot;, &quot;\n&quot;, &quot;\r&quot;, &quot;\t&quot;) _
329 Finally:
330 Escape = sEscape
331 SF_Utils._ExitFunction(cstThisSub)
332 Exit Function
333 Catch:
334 GoTo Finally
335 End Function &apos; ScriptForge.SF_String.Escape
337 REM -----------------------------------------------------------------------------
338 Public Function ExpandTabs(Optional ByRef InputStr As Variant _
339 , Optional ByVal TabSize As Variant _
340 ) As String
341 &apos;&apos;&apos; Return the input string with each TAB (Chr(9)) character replaced by the adequate number of spaces
342 &apos;&apos;&apos; Args:
343 &apos;&apos;&apos; InputStr: the input string
344 &apos;&apos;&apos; TabSize: defines the TAB positions at TabSize + 1, 2 * TabSize + 1 , ... N * TabSize + 1
345 &apos;&apos;&apos; Default = 8
346 &apos;&apos;&apos; Returns:
347 &apos;&apos;&apos; The input string with spaces replacing the TAB characters
348 &apos;&apos;&apos; If the input string contains line breaks, the TAB positions are reset
349 &apos;&apos;&apos; Examples:
350 &apos;&apos;&apos; SF_String.ExpandTabs(&quot;abc&quot; &amp; SF_String.sfTAB &amp; SF_String.sfTAB &amp; &quot;def&quot;, 4) returns &quot;abc def&quot;
351 &apos;&apos;&apos; SF_String.ExpandTabs(&quot;abc&quot; &amp; SF_String.sfTAB &amp; &quot;def&quot; &amp; SF_String.sfLF &amp; SF_String.sfTAB &amp; &quot;ghi&quot;)
352 &apos;&apos;&apos; returns &quot;abc def&quot; &amp; SF_String.sfLF &amp; &quot; ghi&quot;
354 Dim sExpanded As String &apos; Return value
355 Dim lCharPosition As Long &apos; Position of current character in current line in expanded string
356 Dim lSpaces As Long &apos; Spaces counter
357 Dim sChar As String &apos; A single character
358 Dim i As Long
359 Const cstTabSize = 8
360 Const cstThisSub = &quot;String.ExpandTabs&quot;
361 Const cstSubArgs = &quot;InputStr, [TabSize=8]&quot;
363 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
364 sExpanded = &quot;&quot;
366 Check:
367 If IsMissing(TabSize) Or IsEmpty(TabSize) Then TabSize = cstTabSize
368 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
369 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
370 If Not SF_Utils._Validate(TabSize, &quot;TabSize&quot;, V_NUMERIC) Then GoTo Finally
371 End If
372 If TabSize &lt;= 0 Then TabSize = cstTabSize
374 Try:
375 lCharPosition = 0
376 If Len(InputStr) &gt; 0 Then
377 For i = 1 To Len(InputStr)
378 sChar = Mid(InputStr, i, 1)
379 Select Case sChar
380 Case SF_String.sfLF, Chr(12), SF_String.sfCR, Chr(28), Chr(29), Chr(30), Chr(133), Chr(8232), Chr(8233)
381 sExpanded = sExpanded &amp; sChar
382 lCharPosition = 0
383 Case SF_String.sfTAB
384 lSpaces = Int(lCharPosition / TabSize + 1) * TabSize - lCharPosition
385 sExpanded = sExpanded &amp; Space(lSpaces)
386 lCharPosition = lCharPosition + lSpaces
387 Case Else
388 sExpanded = sExpanded &amp; sChar
389 lCharPosition = lCharPosition + 1
390 End Select
391 Next i
392 End If
394 Finally:
395 ExpandTabs = sExpanded
396 SF_Utils._ExitFunction(cstThisSub)
397 Exit Function
398 Catch:
399 GoTo Finally
400 End Function &apos; ScriptForge.SF_String.ExpandTabs
402 REM -----------------------------------------------------------------------------
403 Public Function FilterNotPrintable(Optional ByRef InputStr As Variant _
404 , Optional ByVal ReplacedBy As Variant _
405 ) As String
406 &apos;&apos;&apos; Return the input string in which all the not printable characters are replaced by ReplacedBy
407 &apos;&apos;&apos; Among others, control characters (Ascii &lt;= 1F) are not printable
408 &apos;&apos;&apos; Args:
409 &apos;&apos;&apos; InputStr: the input string
410 &apos;&apos;&apos; ReplacedBy: zero, one or more characters replacing the found not printable characters
411 &apos;&apos;&apos; Default = the zero-length string
412 &apos;&apos;&apos; Returns:
413 &apos;&apos;&apos; The input string in which all the not printable characters are replaced by ReplacedBy
414 &apos;&apos;&apos; Examples:
415 &apos;&apos;&apos; SF_String.FilterNotPrintable(&quot;àén ΣlPµ&quot; &amp; Chr(10) &amp; &quot; Русский&quot;, &quot;\n&quot;) returns &quot;àén ΣlPµ\n Русский&quot;
417 Dim sPrintable As String &apos; Return value
418 Dim bPrintable As Boolean &apos; Is a single character printable ?
419 Dim lLength As Long &apos; Length of InputStr
420 Dim lReplace As Long &apos; Length of ReplacedBy
421 Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
422 Dim oLocale As Object &apos; com.sun.star.lang.Locale
423 Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
424 Dim sChar As String &apos; A single character
425 Dim lPRINTABLE As Long : lPRINTABLE = com.sun.star.i18n.KCharacterType.PRINTABLE
426 Dim i As Long
427 Const cstThisSub = &quot;String.FilterNotPrintable&quot;
428 Const cstSubArgs = &quot;InputStr, [ReplacedBy=&quot;&quot;&quot;&quot;]&quot;
430 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
431 sPrintable = &quot;&quot;
433 Check:
434 If IsMissing(ReplacedBy) Or IsEmpty(ReplacedBy) Then ReplacedBy = &quot;&quot;
435 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
436 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
437 If Not SF_Utils._Validate(ReplacedBy, &quot;ReplacedBy&quot;, V_STRING) Then GoTo Finally
438 End If
440 Try:
441 lLength = Len(InputStr)
442 lReplace = Len(ReplacedBy)
443 If lLength &gt; 0 Then
444 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
445 Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
446 For i = 0 To lLength - 1
447 sChar = Mid(InputStr, i + 1, 1)
448 lType = oChar.getCharacterType(sChar, 0, oLocale)
449 &apos; Parenthses (), [], {} have a KCharacterType = 0
450 bPrintable = ( (lType And lPRINTABLE) = lPRINTABLE Or (lType = 0 And Asc(sChar) &lt;= 127) )
451 If Not bPrintable Then
452 If lReplace &gt; 0 Then sPrintable = sPrintable &amp; ReplacedBy
453 Else
454 sPrintable = sPrintable &amp; sChar
455 End If
456 Next i
457 End If
459 Finally:
460 FilterNotPrintable = sPrintable
461 SF_Utils._ExitFunction(cstThisSub)
462 Exit Function
463 Catch:
464 GoTo Finally
465 End Function &apos; ScriptForge.SF_String.FilterNotPrintable
467 REM -----------------------------------------------------------------------------
468 Public Function FindRegex(Optional ByRef InputStr As Variant _
469 , Optional ByVal Regex As Variant _
470 , Optional ByRef Start As Variant _
471 , Optional ByVal CaseSensitive As Variant _
472 , Optional ByVal Forward As Variant _
473 ) As String
474 &apos;&apos;&apos; Find in InputStr a substring matching a given regular expression
475 &apos;&apos;&apos; Args:
476 &apos;&apos;&apos; InputStr: the input string to be searched for the expression
477 &apos;&apos;&apos; Regex: the regular expression
478 &apos;&apos;&apos; Start (passed by reference): where to start searching from
479 &apos;&apos;&apos; Should be = 1 (Forward = True) or = Len(InputStr) (Forward = False) the 1st time
480 &apos;&apos;&apos; After execution points to the first character of the found substring
481 &apos;&apos;&apos; CaseSensitive: default = False
482 &apos;&apos;&apos; Forward: True (default) or False (backward)
483 &apos;&apos;&apos; Returns:
484 &apos;&apos;&apos; The found substring matching the regular expression
485 &apos;&apos;&apos; A zero-length string if not found (Start is set to 0)
486 &apos;&apos;&apos; Examples:
487 &apos;&apos;&apos; Dim lStart As Long : lStart = 1
488 &apos;&apos;&apos; SF_String.FindRegex(&quot;abCcdefghHij&quot;, &quot;C.*H&quot;, lStart, CaseSensitive := True) returns &quot;CcdefghH&quot;
489 &apos;&apos;&apos; Above statement may be reexecuted for searching the same or another pattern
490 &apos;&apos;&apos; by starting from lStart + Len(matching string)
492 Dim sOutput As String &apos; Return value
493 Dim oTextSearch As Object &apos; com.sun.star.util.TextSearch
494 Dim vOptions As Variant &apos; com.sun.star.util.SearchOptions
495 Dim lEnd As Long &apos; Upper limit of search area
496 Dim vResult As Object &apos; com.sun.star.util.SearchResult
497 Const cstThisSub = &quot;String.FindRegex&quot;
498 Const cstSubArgs = &quot;InputStr, Regex, [Start=1], [CaseSensitive=False], [Forward=True]&quot;
500 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
501 sOutput = &quot;&quot;
503 Check:
504 If IsMissing(Start) Or IsEmpty(Start) Then Start = 1
505 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
506 If IsMissing(Forward) Or IsEmpty(Forward) Then Forward = True
507 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
508 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
509 If Not SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Finally
510 If Not SF_Utils._Validate(Start, &quot;Start&quot;, V_NUMERIC) Then GoTo Finally
511 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
512 If Not SF_Utils._Validate(Forward, &quot;Forward&quot;, V_BOOLEAN) Then GoTo Finally
513 End If
514 If Start &lt;= 0 Or Start &gt; Len(InputStr) Then GoTo Finally
516 Try:
517 sOutput = &quot;&quot;
518 Set oTextSearch = SF_Utils._GetUNOService(&quot;TextSearch&quot;)
519 &apos; Set pattern search options
520 vOptions = SF_Utils._GetUNOService(&quot;SearchOptions&quot;)
521 With vOptions
522 .searchString = Regex
523 If CaseSensitive Then .transliterateFlags = 0 Else .transliterateFlags = com.sun.star.i18n.TransliterationModules.IGNORE_CASE
524 End With
525 &apos; Run search
526 With oTextSearch
527 .setOptions(vOptions)
528 If Forward Then
529 lEnd = Len(InputStr)
530 vResult = .searchForward(InputStr, Start - 1, lEnd)
531 Else
532 lEnd = 1
533 vResult = .searchBackward(InputStr, Start, lEnd - 1)
534 End If
535 End With
536 &apos; https://api.libreoffice.org/docs/idl/ref/structcom_1_1sun_1_1star_1_1util_1_1SearchResult.html
537 With vResult
538 If .subRegExpressions &gt;= 1 Then
539 If Forward Then
540 Start = .startOffset(0) + 1
541 lEnd = .endOffset(0) + 1
542 Else
543 Start = .endOffset(0) + 1
544 lEnd = .startOffset(0) + 1
545 End If
546 sOutput = Mid(InputStr, Start, lEnd - Start)
547 Else
548 Start = 0
549 End If
550 End With
552 Finally:
553 FindRegex = sOutput
554 SF_Utils._ExitFunction(cstThisSub)
555 Exit Function
556 Catch:
557 GoTo Finally
558 End Function &apos; ScriptForge.SF_String.FindRegex
560 REM -----------------------------------------------------------------------------
561 Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
562 &apos;&apos;&apos; Return the actual value of the given property
563 &apos;&apos;&apos; Args:
564 &apos;&apos;&apos; PropertyName: the name of the property as a string
565 &apos;&apos;&apos; Returns:
566 &apos;&apos;&apos; The actual value of the property
567 &apos;&apos;&apos; Exceptions
568 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
570 Const cstThisSub = &quot;String.GetProperty&quot;
571 Const cstSubArgs = &quot;PropertyName&quot;
573 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
574 GetProperty = Null
576 Check:
577 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
578 If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
579 End If
581 Try:
582 Select Case UCase(PropertyName)
583 Case &quot;SFCR&quot; : GetProperty = sfCR
584 Case &quot;SFCRLF&quot; : GetProperty = sfCRLF
585 Case &quot;SFLF&quot; : GetProperty = sfLF
586 Case &quot;SFNEWLINE&quot; : GetProperty = sfNEWLINE
587 Case &quot;SFTAB&quot; : GetProperty = sfTAB
588 Case Else
589 End Select
591 Finally:
592 SF_Utils._ExitFunction(cstThisSub)
593 Exit Function
594 Catch:
595 GoTo Finally
596 End Function &apos; ScriptForge.SF_String.GetProperty
598 REM -----------------------------------------------------------------------------
599 Public Function HashStr(Optional ByVal InputStr As Variant _
600 , Optional ByVal Algorithm As Variant _
601 ) As String
602 &apos;&apos;&apos; Return an hexadecimal string representing a checksum of the given input string
603 &apos;&apos;&apos; Next algorithms are supported: MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
604 &apos;&apos;&apos; Args:
605 &apos;&apos;&apos; InputStr: the string to be hashed
606 &apos;&apos;&apos; Algorithm: The hashing algorithm to use
607 &apos;&apos;&apos; Returns:
608 &apos;&apos;&apos; The requested checksum as a string. Hexadecimal digits are lower-cased
609 &apos;&apos;&apos; A zero-length string when an error occurred
610 &apos;&apos;&apos; Example:
611 &apos;&apos;&apos; Print SF_String.HashStr(&quot;œ∑¡™£¢∞§¶•ªº–≠œ∑´®†¥¨ˆøπ“‘åß∂ƒ©˙∆˚¬&quot;, &quot;MD5&quot;) &apos; 616eb9c513ad07cd02924b4d285b9987
613 Dim sHash As String &apos; Return value
614 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_String__HashStr&quot;
615 Const cstThisSub = &quot;String.HashStr&quot;
616 Const cstSubArgs = &quot;InputStr, Algorithm=&quot;&quot;MD5&quot;&quot;|&quot;&quot;SHA1&quot;&quot;|&quot;&quot;SHA224&quot;&quot;|&quot;&quot;SHA256&quot;&quot;|&quot;&quot;SHA384&quot;&quot;|&quot;&quot;SHA512&quot;&quot;&quot;
618 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
619 sHash = &quot;&quot;
621 Check:
622 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
623 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
624 If Not SF_Utils._Validate(Algorithm, &quot;Algorithm&quot;, V_STRING _
625 , Array(&quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA224&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot;)) Then GoTo Finally
626 End If
628 Try:
629 With ScriptForge.SF_Session
630 sHash = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
631 , InputStr, LCase(Algorithm))
632 End With
634 Finally:
635 HashStr = sHash
636 SF_Utils._ExitFunction(cstThisSub)
637 Exit Function
638 Catch:
639 GoTo Finally
640 End Function &apos; ScriptForge.SF_String.HashStr
642 REM -----------------------------------------------------------------------------
643 Public Function HtmlEncode(Optional ByRef InputStr As Variant) As String
644 &apos;&apos;&apos; &amp;-encoding of the input string (e.g. &quot;é&quot; becomes &quot;&amp;eacute;&quot; or numeric equivalent
645 &apos;&apos;&apos; Args:
646 &apos;&apos;&apos; InputStr: the input string
647 &apos;&apos;&apos; Returns:
648 &apos;&apos;&apos; the encoded string
649 &apos;&apos;&apos; Examples:
650 &apos;&apos;&apos; SF_String.HtmlEncode(&quot;&lt;a href=&quot;&quot;https://a.b.com&quot;&quot;&gt;From α to ω&lt;/a&gt;&quot;)
651 &apos;&apos;&apos; returns &quot;&amp;lt;a href=&amp;quot;https://a.b.com&amp;quot;&amp;gt;From &amp;#945; to &amp;#969;&amp;lt;/a&amp;gt;&quot;
653 Dim sEncode As String &apos; Return value
654 Dim lPos As Long &apos; Position in InputStr
655 Dim sChar As String &apos; A single character extracted from InputStr
656 Dim i As Long
657 Const cstThisSub = &quot;String.HtmlEncode&quot;
658 Const cstSubArgs = &quot;InputStr&quot;
660 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
661 sEncode = &quot;&quot;
663 Check:
664 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
665 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
666 End If
668 Try:
669 If Len(InputStr) &gt; 0 Then
670 lPos = 1
671 sEncode = InputStr
672 Do While lPos &lt;= Len(sEncode)
673 sChar = Mid(sEncode, lPos, 1)
674 &apos; Leave as is or encode every single char
675 Select Case sChar
676 Case &quot;&quot;&quot;&quot; : sChar = &quot;&amp;quot;&quot;
677 Case &quot;&amp;&quot; : sChar = &quot;&amp;amp;&quot;
678 Case &quot;&lt;&quot; : sChar = &quot;&amp;lt;&quot;
679 Case &quot;&gt;&quot; : sChar = &quot;&amp;gt;&quot;
680 Case &quot;&apos;&quot; : sChar = &quot;&amp;apos;&quot;
681 Case &quot;:&quot;, &quot;/&quot;, &quot;?&quot;, &quot;#&quot;, &quot;[&quot;, &quot;]&quot;, &quot;@&quot; &apos; Reserved characters
682 Case SF_String.sfCR : sChar = &quot;&quot; &apos; Carriage return
683 Case SF_String.sfLF : sChar = &quot;&lt;br&gt;&quot; &apos; Line Feed
684 Case &lt; Chr(126)
685 Case &quot;&quot; : sChar = &quot;&amp;euro;&quot;
686 Case Else : sChar = &quot;&amp;#&quot; &amp; Asc(sChar) &amp; &quot;;&quot;
687 End Select
688 If Len(sChar) = 1 Then
689 Mid(sEncode, lPos, 1) = sChar
690 Else
691 sEncode = Left(sEncode, lPos - 1) &amp; sChar &amp; Mid(sEncode, lPos + 1)
692 End If
693 lPos = lPos + Len(sChar)
694 Loop
695 End If
697 Finally:
698 HtmlEncode = sEncode
699 SF_Utils._ExitFunction(cstThisSub)
700 Exit Function
701 Catch:
702 GoTo Finally
703 End Function &apos; ScriptForge.SF_String.HtmlEncode
705 REM -----------------------------------------------------------------------------
706 Public Function IsADate(Optional ByRef InputStr As Variant _
707 , Optional ByVal DateFormat _
708 ) As Boolean
709 &apos;&apos;&apos; Return True if the string is a valid date respecting the given format
710 &apos;&apos;&apos; Args:
711 &apos;&apos;&apos; InputStr: the input string
712 &apos;&apos;&apos; DateFormat: either YYYY-MM-DD (default), DD-MM-YYYY or MM-DD-YYYY
713 &apos;&apos;&apos; The dash (-) may be replaced by a dot (.), a slash (/) or a space
714 &apos;&apos;&apos; Returns:
715 &apos;&apos;&apos; True if the string contains a valid date and there is at least one character
716 &apos;&apos;&apos; False otherwise or if the date format is invalid
717 &apos;&apos;&apos; Examples:
718 &apos;&apos;&apos; SF_String.IsADate(&quot;2019-12-31&quot;, &quot;YYYY-MM-DD&quot;) returns True
720 Dim bADate As Boolean &apos; Return value
721 Dim sFormat As String &apos; Alias for DateFormat
722 Dim sRegex As String &apos; The regex to check against the input string
723 Const cstFormat = &quot;YYYY-MM-DD&quot; &apos; Default date format
724 Const cstFormatRegex = &quot;(YYYY[- /.]MM[- /.]DD|MM[- /.]DD[- /.]YYYY|DD[- /.]MM[- /.]YYYY)&quot;
725 &apos; The regular expression the format must match
726 Const cstThisSub = &quot;String.IsADate&quot;
727 Const cstSubArgs = &quot;InputStr, [DateFormat=&quot;&quot;&quot; &amp; cstFormat &amp; &quot;&quot;&quot;]&quot;
729 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
730 bADate = False
732 Check:
733 If IsMissing(DateFormat) Or IsEmpty(DateFormat) Then DateFormat = &quot;YYYY-MM-DD&quot;
734 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
735 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
736 If Not SF_Utils._Validate(DateFormat, &quot;DateFormat&quot;, V_STRING) Then GoTo Finally
737 End If
738 sFormat = UCase(DateFormat)
739 If Len(sFormat) &lt;&gt; Len(cstFormat)Then GoTo Finally
740 If sFormat &lt;&gt; cstFormat Then &apos; Do not check if default format
741 If Not SF_String.IsRegex(sFormat, cstFormatRegex) Then GoTo Finally
742 End If
744 Try:
745 If Len(InputStr) = Len(DateFormat) Then
746 sRegex = ReplaceStr(sFormat, Array(&quot;YYYY&quot;, &quot;MM&quot;, &quot;DD&quot;) _
747 , Array(REGEXDATEYEAR, REGEXDATEMONTH, REGEXDATEDAY) _
748 , CaseSensitive := False)
749 bADate = SF_String.IsRegex(InputStr, sRegex, CaseSensitive := False)
750 End If
752 Finally:
753 IsADate = bADate
754 SF_Utils._ExitFunction(cstThisSub)
755 Exit Function
756 Catch:
757 GoTo Finally
758 End Function &apos; ScriptForge.SF_String.IsADate
760 REM -----------------------------------------------------------------------------
761 Public Function IsAlpha(Optional ByRef InputStr As Variant) As Boolean
762 &apos;&apos;&apos; Return True if all characters in the string are alphabetic
763 &apos;&apos;&apos; Alphabetic characters are those characters defined in the Unicode character database as “Letter”
764 &apos;&apos;&apos; Args:
765 &apos;&apos;&apos; InputStr: the input string
766 &apos;&apos;&apos; Returns:
767 &apos;&apos;&apos; True if the string is alphabetic and there is at least one character, False otherwise
768 &apos;&apos;&apos; Examples:
769 &apos;&apos;&apos; SF_String.IsAlpha(&quot;àénΣlPµ&quot;) returns True
770 &apos;&apos;&apos; Note:
771 &apos;&apos;&apos; Use SF_String.IsRegex(&quot;...&quot;, REGEXALPHA) to limit characters to latin alphabet
773 Dim bAlpha As Boolean &apos; Return value
774 Dim lLength As Long &apos; Length of InputStr
775 Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
776 Dim oLocale As Object &apos; com.sun.star.lang.Locale
777 Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
778 Dim lLETTER As Long : lLETTER = com.sun.star.i18n.KCharacterType.LETTER
779 Dim i As Long
780 Const cstThisSub = &quot;String.IsAlpha&quot;
781 Const cstSubArgs = &quot;InputStr&quot;
783 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
784 bAlpha = False
786 Check:
787 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
788 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
789 End If
791 Try:
792 lLength = Len(InputStr)
793 If lLength &gt; 0 Then
794 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
795 Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
796 For i = 0 To lLength - 1
797 lType = oChar.getCharacterType(InputStr, i, oLocale)
798 bAlpha = ( (lType And lLETTER) = lLETTER )
799 If Not bAlpha Then Exit For
800 Next i
801 End If
803 Finally:
804 IsAlpha = bAlpha
805 SF_Utils._ExitFunction(cstThisSub)
806 Exit Function
807 Catch:
808 GoTo Finally
809 End Function &apos; ScriptForge.SF_String.IsAlpha
811 REM -----------------------------------------------------------------------------
812 Public Function IsAlphaNum(Optional ByRef InputStr As Variant) As Boolean
813 &apos;&apos;&apos; Return True if all characters in the string are alphabetic, digits or &quot;_&quot; (underscore)
814 &apos;&apos;&apos; The first character must not be a digit
815 &apos;&apos;&apos; Args:
816 &apos;&apos;&apos; InputStr: the input string
817 &apos;&apos;&apos; Returns:
818 &apos;&apos;&apos; True if the string is alphanumeric and there is at least one character, False otherwise
819 &apos;&apos;&apos; Examples:
820 &apos;&apos;&apos; SF_String.IsAlphaNum(&quot;_ABC_123456_abcàénΣlPµ&quot;) returns True
822 Dim bAlphaNum As Boolean &apos; Return value
823 Dim sInputStr As String &apos; Alias of InputStr without underscores
824 Dim sFirst As String &apos; Leftmost character of InputStr
825 Dim lLength As Long &apos; Length of InputStr
826 Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
827 Dim oLocale As Object &apos; com.sun.star.lang.Locale
828 Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
829 Dim lLETTER As Long : lLETTER = com.sun.star.i18n.KCharacterType.LETTER
830 Dim lDIGIT As Long : lDIGIT = com.sun.star.i18n.KCharacterType.DIGIT
831 Dim i As Long
832 Const cstThisSub = &quot;String.IsAlphaNum&quot;
833 Const cstSubArgs = &quot;InputStr&quot;
835 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
836 bAlphaNum = False
838 Check:
839 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
840 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
841 End If
843 Try:
844 lLength = Len(InputStr)
845 If lLength &gt; 0 Then
846 sFirst = Left(InputStr, 1)
847 bAlphanum = ( sFirst &lt; &quot;0&quot; Or sFirst &gt; &quot;9&quot; )
848 If bAlphaNum Then
849 sInputStr = Replace(InputStr, &quot;_&quot;, &quot;A&quot;) &apos; Replace by an arbitrary alphabetic character
850 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
851 Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
852 For i = 0 To lLength - 1
853 lType = oChar.getCharacterType(sInputStr, i, oLocale)
854 bAlphaNum = ( (lType And lLETTER) = lLETTER _
855 Or (lType And lDIGIT) = lDIGIT )
856 If Not bAlphaNum Then Exit For
857 Next i
858 End If
859 End If
861 Finally:
862 IsAlphaNum = bAlphaNum
863 SF_Utils._ExitFunction(cstThisSub)
864 Exit Function
865 Catch:
866 GoTo Finally
867 End Function &apos; ScriptForge.SF_String.IsAlphaNum
869 REM -----------------------------------------------------------------------------
870 Public Function IsAscii(Optional ByRef InputStr As Variant) As Boolean
871 &apos;&apos;&apos; Return True if all characters in the string are Ascii characters
872 &apos;&apos;&apos; Ascii characters are those characters defined between &amp;H00 and &amp;H7F
873 &apos;&apos;&apos; Args:
874 &apos;&apos;&apos; InputStr: the input string
875 &apos;&apos;&apos; Returns:
876 &apos;&apos;&apos; True if the string is Ascii and there is at least one character, False otherwise
877 &apos;&apos;&apos; Examples:
878 &apos;&apos;&apos; SF_String.IsAscii(&quot;a%?,25&quot;) returns True
880 Dim bAscii As Boolean &apos; Return value
881 Dim lLength As Long &apos; Length of InputStr
882 Dim sChar As String &apos; Single character
883 Dim i As Long
884 Const cstThisSub = &quot;String.IsAscii&quot;
885 Const cstSubArgs = &quot;InputStr&quot;
887 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
888 bAscii = False
890 Check:
891 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
892 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
893 End If
895 Try:
896 lLength = Len(InputStr)
897 If lLength &gt; 0 Then
898 For i = 1 To lLength
899 sChar = Mid(InputStr, i, 1)
900 bAscii = ( Asc(sChar) &lt;= 127 )
901 If Not bAscii Then Exit For
902 Next i
903 End If
905 Finally:
906 IsAscii = bAscii
907 SF_Utils._ExitFunction(cstThisSub)
908 Exit Function
909 Catch:
910 GoTo Finally
911 End Function &apos; ScriptForge.SF_String.IsAscii
913 REM -----------------------------------------------------------------------------
914 Public Function IsDigit(Optional ByRef InputStr As Variant) As Boolean
915 &apos;&apos;&apos; Return True if all characters in the string are digits
916 &apos;&apos;&apos; Args:
917 &apos;&apos;&apos; InputStr: the input string
918 &apos;&apos;&apos; Returns:
919 &apos;&apos;&apos; True if the string contains only digits and there is at least one character, False otherwise
920 &apos;&apos;&apos; Examples:
921 &apos;&apos;&apos; SF_String.IsDigit(&quot;123456&quot;) returns True
923 Dim bDigit As Boolean &apos; Return value
924 Const cstThisSub = &quot;String.IsDigit&quot;
925 Const cstSubArgs = &quot;InputStr&quot;
927 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
928 bDigit = False
930 Check:
931 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
932 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
933 End If
935 Try:
936 If Len(InputStr) &gt; 0 Then bDigit = SF_String.IsRegex(InputStr, REGEXDIGITS, CaseSensitive := False)
938 Finally:
939 IsDigit = bDigit
940 SF_Utils._ExitFunction(cstThisSub)
941 Exit Function
942 Catch:
943 GoTo Finally
944 End Function &apos; ScriptForge.SF_String.IsDigit
946 REM -----------------------------------------------------------------------------
947 Public Function IsEmail(Optional ByRef InputStr As Variant) As Boolean
948 &apos;&apos;&apos; Return True if the string is a valid email address
949 &apos;&apos;&apos; Args:
950 &apos;&apos;&apos; InputStr: the input string
951 &apos;&apos;&apos; Returns:
952 &apos;&apos;&apos; True if the string contains an email address and there is at least one character, False otherwise
953 &apos;&apos;&apos; Examples:
954 &apos;&apos;&apos; SF_String.IsEmail(&quot;first.last@something.org&quot;) returns True
956 Dim bEmail As Boolean &apos; Return value
957 Const cstThisSub = &quot;String.IsEmail&quot;
958 Const cstSubArgs = &quot;InputStr&quot;
960 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
961 bEmail = False
963 Check:
964 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
965 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
966 End If
968 Try:
969 If Len(InputStr) &gt; 0 Then bEmail = SF_String.IsRegex(InputStr, REGEXEMAIL, CaseSensitive := False)
971 Finally:
972 IsEmail = bEmail
973 SF_Utils._ExitFunction(cstThisSub)
974 Exit Function
975 Catch:
976 GoTo Finally
977 End Function &apos; ScriptForge.SF_String.IsEmail
979 REM -----------------------------------------------------------------------------
980 Public Function IsFileName(Optional ByRef InputStr As Variant _
981 , Optional ByVal OSName As Variant _
982 ) As Boolean
983 &apos;&apos;&apos; Return True if the string is a valid filename in a given operating system
984 &apos;&apos;&apos; Args:
985 &apos;&apos;&apos; InputStr: the input string
986 &apos;&apos;&apos; OSName: Windows, Linux, macOS or Solaris
987 &apos;&apos;&apos; The default is the current operating system on which the script is run
988 &apos;&apos;&apos; Returns:
989 &apos;&apos;&apos; True if the string contains a valid filename and there is at least one character, False otherwise
990 &apos;&apos;&apos; Examples:
991 &apos;&apos;&apos; SF_String.IsFileName(&quot;/home/a file name.odt&quot;, &quot;LINUX&quot;) returns True
993 Dim bFileName As Boolean &apos; Return value
994 Dim sRegex As String &apos; Regex to apply depending on OS
995 Const cstThisSub = &quot;String.IsFileName&quot;
996 Const cstSubArgs = &quot;InputStr, [OSName=&quot;&quot;Windows&quot;&quot;|&quot;&quot;Linux&quot;&quot;|&quot;&quot;macOS&quot;&quot;|Solaris&quot;&quot;]&quot;
998 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
999 bFileName = False
1001 Check:
1002 If IsMissing(OSName) Or IsEmpty(OSName) Then
1003 If _SF_.OSname = &quot;&quot; Then _SF_.OSName = SF_Platform.OSName
1004 OSName = _SF_.OSName
1005 End If
1006 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1007 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1008 If Not SF_Utils._Validate(OSName, &quot;OSName&quot;, V_STRING, Array(&quot;Windows&quot;, &quot;Linux&quot;, &quot;macOS&quot;, &quot;Solaris&quot;)) Then GoTo Finally
1009 End If
1011 Try:
1012 If Len(InputStr) &gt; 0 Then
1013 Select Case UCase(OSName)
1014 Case &quot;LINUX&quot;, &quot;MACOS&quot;, &quot;SOLARIS&quot; : sRegex = REGEXFILELINUX
1015 Case &quot;WINDOWS&quot; : sRegex = REGEXFILEWIN
1016 End Select
1017 bFileName = SF_String.IsRegex(InputStr, sRegex, CaseSensitive := False)
1018 End If
1020 Finally:
1021 IsFileName = bFileName
1022 SF_Utils._ExitFunction(cstThisSub)
1023 Exit Function
1024 Catch:
1025 GoTo Finally
1026 End Function &apos; ScriptForge.SF_String.IsFileName
1028 REM -----------------------------------------------------------------------------
1029 Public Function IsHexDigit(Optional ByRef InputStr As Variant) As Boolean
1030 &apos;&apos;&apos; Return True if all characters in the string are hexadecimal digits
1031 &apos;&apos;&apos; Args:
1032 &apos;&apos;&apos; InputStr: the input string
1033 &apos;&apos;&apos; Returns:
1034 &apos;&apos;&apos; True if the string contains only hexadecimal igits and there is at least one character
1035 &apos;&apos;&apos; The prefixes &quot;0x&quot; and &quot;&amp;H&quot; are admitted
1036 &apos;&apos;&apos; False otherwise
1037 &apos;&apos;&apos; Examples:
1038 &apos;&apos;&apos; SF_String.IsHexDigit(&quot;&amp;H00FF&quot;) returns True
1040 Dim bHexDigit As Boolean &apos; Return value
1041 Const cstThisSub = &quot;String.IsHexDigit&quot;
1042 Const cstSubArgs = &quot;InputStr&quot;
1044 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1045 bHexDigit = False
1047 Check:
1048 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1049 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1050 End If
1052 Try:
1053 If Len(InputStr) &gt; 0 Then bHexDigit = SF_String.IsRegex(InputStr, REGEXHEXA, CaseSensitive := False)
1055 Finally:
1056 IsHexDigit = bHexDigit
1057 SF_Utils._ExitFunction(cstThisSub)
1058 Exit Function
1059 Catch:
1060 GoTo Finally
1061 End Function &apos; ScriptForge.SF_String.IsHexDigit
1063 REM -----------------------------------------------------------------------------
1064 Public Function IsIPv4(Optional ByRef InputStr As Variant) As Boolean
1065 &apos;&apos;&apos; Return True if the string is a valid IPv4 address
1066 &apos;&apos;&apos; Args:
1067 &apos;&apos;&apos; InputStr: the input string
1068 &apos;&apos;&apos; Returns:
1069 &apos;&apos;&apos; True if the string contains a valid IPv4 address and there is at least one character, False otherwise
1070 &apos;&apos;&apos; Examples:
1071 &apos;&apos;&apos; SF_String.IsIPv4(&quot;192.168.1.50&quot;) returns True
1073 Dim bIPv4 As Boolean &apos; Return value
1074 Const cstThisSub = &quot;String.IsIPv4&quot;
1075 Const cstSubArgs = &quot;InputStr&quot;
1077 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1078 bIPv4 = False
1080 Check:
1081 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1082 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1083 End If
1085 Try:
1086 If Len(InputStr) &gt; 0 Then bIPv4 = SF_String.IsRegex(InputStr, REGEXIPV4, CaseSensitive := False)
1088 Finally:
1089 IsIPv4 = bIPv4
1090 SF_Utils._ExitFunction(cstThisSub)
1091 Exit Function
1092 Catch:
1093 GoTo Finally
1094 End Function &apos; ScriptForge.SF_String.IsIPv4
1096 REM -----------------------------------------------------------------------------
1097 Public Function IsLike(Optional ByRef InputStr As Variant _
1098 , Optional ByVal Pattern As Variant _
1099 , Optional ByVal CaseSensitive As Variant _
1100 ) As Boolean
1101 &apos;&apos;&apos; Returns True if the whole input string matches a given pattern containing wildcards
1102 &apos;&apos;&apos; Args:
1103 &apos;&apos;&apos; InputStr: the input string
1104 &apos;&apos;&apos; Pattern: the pattern as a string
1105 &apos;&apos;&apos; Admitted wildcard are: the &quot;?&quot; represents any single character
1106 &apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
1107 &apos;&apos;&apos; CaseSensitive: default = False
1108 &apos;&apos;&apos; Returns:
1109 &apos;&apos;&apos; True if a match is found
1110 &apos;&apos;&apos; Zero-length input or pattern strings always return False
1111 &apos;&apos;&apos; Examples:
1112 &apos;&apos;&apos; SF_String.IsLike(&quot;aAbB&quot;, &quot;?A*&quot;) returns True
1113 &apos;&apos;&apos; SF_String.IsLike(&quot;C:\a\b\c\f.odb&quot;, &quot;?:*.*&quot;) returns True
1115 Dim bLike As Boolean &apos; Return value
1116 &apos; Build an equivalent regular expression by escaping the special characters present in Pattern
1117 Dim sRegex As String &apos; Equivalent regular expression
1118 Const cstSpecialChars = &quot;\,^,$,.,|,+,(,),[,{,?,*&quot; &apos; List of special chars in regular expressions
1119 Const cstEscapedChars = &quot;\\,\^,\$,\.,\|,\+,\(,\),\[,\{,.,.*&quot;
1121 Const cstThisSub = &quot;String.IsLike&quot;
1122 Const cstSubArgs = &quot;InputStr, Pattern, [CaseSensitive=False]&quot;
1124 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1125 bLike = False
1127 Check:
1128 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
1129 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1130 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1131 If Not SF_Utils._Validate(Pattern, &quot;Pattern&quot;, V_STRING) Then GoTo Finally
1132 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
1133 End If
1135 Try:
1136 If Len(InputStr) &gt; 0 And Len(Pattern) &gt; 0 Then
1137 &apos; Substitute special chars by escaped chars
1138 sRegex = SF_String.ReplaceStr(Pattern, Split(cstSPecialChars, &quot;,&quot;), Split(cstEscapedChars, &quot;,&quot;))
1139 bLike = SF_String.IsRegex(InputStr, sRegex, CaseSensitive)
1140 End If
1142 Finally:
1143 IsLike = bLike
1144 SF_Utils._ExitFunction(cstThisSub)
1145 Exit Function
1146 Catch:
1147 GoTo Finally
1148 End Function &apos; ScriptForge.SF_String.IsLike
1150 REM -----------------------------------------------------------------------------
1151 Public Function IsLower(Optional ByRef InputStr As Variant) As Boolean
1152 &apos;&apos;&apos; Return True if all characters in the string are in lower case
1153 &apos;&apos;&apos; Non alphabetic characters are ignored
1154 &apos;&apos;&apos; Args:
1155 &apos;&apos;&apos; InputStr: the input string
1156 &apos;&apos;&apos; Returns:
1157 &apos;&apos;&apos; True if the string contains only lower case characters and there is at least one character, False otherwise
1158 &apos;&apos;&apos; Examples:
1159 &apos;&apos;&apos; SF_String.IsLower(&quot;abc&apos;(-xyz&quot;) returns True
1161 Dim bLower As Boolean &apos; Return value
1162 Const cstThisSub = &quot;String.IsLower&quot;
1163 Const cstSubArgs = &quot;InputStr&quot;
1165 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1166 bLower = False
1168 Check:
1169 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1170 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1171 End If
1173 Try:
1174 If Len(InputStr) &gt; 0 Then bLower = ( StrComp(InputStr, LCase(InputStr), 1) = 0 )
1176 Finally:
1177 IsLower = bLower
1178 SF_Utils._ExitFunction(cstThisSub)
1179 Exit Function
1180 Catch:
1181 GoTo Finally
1182 End Function &apos; ScriptForge.SF_String.IsLower
1184 REM -----------------------------------------------------------------------------
1185 Public Function IsPrintable(Optional ByRef InputStr As Variant) As Boolean
1186 &apos;&apos;&apos; Return True if all characters in the string are printable
1187 &apos;&apos;&apos; In particular, control characters (Ascii &lt;= 1F) are not printable
1188 &apos;&apos;&apos; Args:
1189 &apos;&apos;&apos; InputStr: the input string
1190 &apos;&apos;&apos; Returns:
1191 &apos;&apos;&apos; True if the string is printable and there is at least one character, False otherwise
1192 &apos;&apos;&apos; Examples:
1193 &apos;&apos;&apos; SF_String.IsPrintable(&quot;àén ΣlPµ Русский&quot;) returns True
1195 Dim bPrintable As Boolean &apos; Return value
1196 Dim lLength As Long &apos; Length of InputStr
1197 Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
1198 Dim oLocale As Object &apos; com.sun.star.lang.Locale
1199 Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
1200 Dim sChar As String &apos; A single character
1201 Dim lPRINTABLE As Long : lPRINTABLE = com.sun.star.i18n.KCharacterType.PRINTABLE
1202 Dim i As Long
1203 Const cstThisSub = &quot;String.IsPrintable&quot;
1204 Const cstSubArgs = &quot;InputStr&quot;
1206 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1207 bPrintable = False
1209 Check:
1210 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1211 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1212 End If
1214 Try:
1215 lLength = Len(InputStr)
1216 If lLength &gt; 0 Then
1217 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
1218 Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
1219 For i = 0 To lLength - 1
1220 sChar = Mid(InputStr, i + 1, 1)
1221 lType = oChar.getCharacterType(sChar, 0, oLocale)
1222 &apos; Parenthses (), [], {} have a KCharacterType = 0
1223 bPrintable = ( (lType And lPRINTABLE) = lPRINTABLE Or (lType = 0 And Asc(sChar) &lt;= 127) )
1224 If Not bPrintable Then Exit For
1225 Next i
1226 End If
1228 Finally:
1229 IsPrintable = bPrintable
1230 SF_Utils._ExitFunction(cstThisSub)
1231 Exit Function
1232 Catch:
1233 GoTo Finally
1234 End Function &apos; ScriptForge.SF_String.IsPrintable
1236 REM -----------------------------------------------------------------------------
1237 Public Function IsRegex(Optional ByRef InputStr As Variant _
1238 , Optional ByVal Regex As Variant _
1239 , Optional ByVal CaseSensitive As Variant _
1240 ) As Boolean
1241 &apos;&apos;&apos; Returns True if the whole input string matches a given regular expression
1242 &apos;&apos;&apos; Args:
1243 &apos;&apos;&apos; InputStr: the input string
1244 &apos;&apos;&apos; Regex: the regular expression as a string
1245 &apos;&apos;&apos; CaseSensitive: default = False
1246 &apos;&apos;&apos; Returns:
1247 &apos;&apos;&apos; True if a match is found
1248 &apos;&apos;&apos; Zero-length input or regex strings always return False
1249 &apos;&apos;&apos; Examples:
1250 &apos;&apos;&apos; SF_String.IsRegex(&quot;aAbB&quot;, &quot;[A-Za-z]+&quot;) returns True
1252 Dim bRegex As Boolean &apos; Return value
1253 Dim lStart As Long &apos; Must be 1
1254 Dim sMatch As String &apos; Matching string
1255 Const cstBegin = &quot;^&quot; &apos; Beginning of line symbol
1256 Const cstEnd = &quot;$&quot; &apos; End of line symbol
1257 Const cstThisSub = &quot;String.IsRegex&quot;
1258 Const cstSubArgs = &quot;InputStr, Regex, [CaseSensitive=False]&quot;
1260 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1261 bRegex = False
1263 Check:
1264 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
1265 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1266 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1267 If Not SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Finally
1268 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
1269 End If
1271 Try:
1272 If Len(InputStr) &gt; 0 And Len(Regex) &gt; 0 Then
1273 &apos; Whole string must match Regex
1274 lStart = 1
1275 If Left(Regex, 1) &lt;&gt; cstBegin Then Regex = cstBegin &amp; Regex
1276 If Right(Regex, 1) &lt;&gt; cstEnd Then Regex = Regex &amp; cstEnd
1277 sMatch = SF_String.FindRegex(InputStr, Regex, lStart, CaseSensitive)
1278 &apos; Match ?
1279 bRegex = ( lStart = 1 And Len(sMatch) = Len(InputStr) )
1280 End If
1282 Finally:
1283 IsRegex = bRegex
1284 SF_Utils._ExitFunction(cstThisSub)
1285 Exit Function
1286 Catch:
1287 GoTo Finally
1288 End Function &apos; ScriptForge.SF_String.IsRegex
1290 REM -----------------------------------------------------------------------------
1291 Public Function IsSheetName(Optional ByRef InputStr As Variant) As Boolean
1292 &apos;&apos;&apos; Return True if the input string can serve as a valid Calc sheet name
1293 &apos;&apos;&apos; The sheet name must not contain the characters [ ] * ? : / \
1294 &apos;&apos;&apos; or the character &apos; (apostrophe) as first or last character.
1296 &apos;&apos;&apos; Args:
1297 &apos;&apos;&apos; InputStr: the input string
1298 &apos;&apos;&apos; Returns:
1299 &apos;&apos;&apos; True if the string is validated as a potential Calc sheet name, False otherwise
1300 &apos;&apos;&apos; Examples:
1301 &apos;&apos;&apos; SF_String.IsSheetName(&quot;1àbc + &quot;&quot;def&quot;&quot;&quot;) returns True
1303 Dim bSheetName As Boolean &apos; Return value
1304 Const cstThisSub = &quot;String.IsSheetName&quot;
1305 Const cstSubArgs = &quot;InputStr&quot;
1307 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1308 bSheetName = False
1310 Check:
1311 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1312 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1313 End If
1315 Try:
1316 If Len(InputStr) &gt; 0 Then
1317 If Left(InputStr, 1) = &quot;&apos;&quot; Or Right(InputStr, 1) = &quot;&apos;&quot; Then
1318 ElseIf InStr(InputStr, &quot;[&quot;) _
1319 + InStr(InputStr, &quot;]&quot;) _
1320 + InStr(InputStr, &quot;*&quot;) _
1321 + InStr(InputStr, &quot;?&quot;) _
1322 + InStr(InputStr, &quot;:&quot;) _
1323 + InStr(InputStr, &quot;/&quot;) _
1324 + InStr(InputStr, &quot;\&quot;) _
1325 = 0 Then
1326 bSheetName = True
1327 End If
1328 End If
1330 Finally:
1331 IsSheetName = bSheetName
1332 SF_Utils._ExitFunction(cstThisSub)
1333 Exit Function
1334 Catch:
1335 GoTo Finally
1336 End Function &apos; ScriptForge.SF_String.IsSheetName
1338 REM -----------------------------------------------------------------------------
1339 Public Function IsTitle(Optional ByRef InputStr As Variant) As Boolean
1340 &apos;&apos;&apos; Return True if the 1st character of every word is in upper case and the other characters are in lower case
1341 &apos;&apos;&apos; Args:
1342 &apos;&apos;&apos; InputStr: the input string
1343 &apos;&apos;&apos; Returns:
1344 &apos;&apos;&apos; True if the string is capitalized and there is at least one character, False otherwise
1345 &apos;&apos;&apos; Examples:
1346 &apos;&apos;&apos; SF_String.IsTitle(&quot;This Is A Title For Jean-Pierre&quot;) returns True
1348 Dim bTitle As Boolean &apos; Return value
1349 Const cstThisSub = &quot;String.IsTitle&quot;
1350 Const cstSubArgs = &quot;InputStr&quot;
1352 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1353 bTitle = False
1355 Check:
1356 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1357 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1358 End If
1360 Try:
1361 If Len(InputStr) &gt; 0 Then bTitle = ( StrComp(InputStr, SF_String.Capitalize(InputStr), 1) = 0 )
1363 Finally:
1364 IsTitle = bTitle
1365 SF_Utils._ExitFunction(cstThisSub)
1366 Exit Function
1367 Catch:
1368 GoTo Finally
1369 End Function &apos; ScriptForge.SF_String.IsTitle
1371 REM -----------------------------------------------------------------------------
1372 Public Function IsUpper(Optional ByRef InputStr As Variant) As Boolean
1373 &apos;&apos;&apos; Return True if all characters in the string are in upper case
1374 &apos;&apos;&apos; Non alphabetic characters are ignored
1375 &apos;&apos;&apos; Args:
1376 &apos;&apos;&apos; InputStr: the input string
1377 &apos;&apos;&apos; Returns:
1378 &apos;&apos;&apos; True if the string contains only upper case characters and there is at least one character, False otherwise
1379 &apos;&apos;&apos; Examples:
1380 &apos;&apos;&apos; SF_String.IsUpper(&quot;ABC&apos;(-XYZ&quot;) returns True
1382 Dim bUpper As Boolean &apos; Return value
1383 Const cstThisSub = &quot;String.IsUpper&quot;
1384 Const cstSubArgs = &quot;InputStr&quot;
1386 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1387 bUpper = False
1389 Check:
1390 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1391 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1392 End If
1394 Try:
1395 If Len(InputStr) &gt; 0 Then bUpper = ( StrComp(InputStr, UCase(InputStr), 1) = 0 )
1397 Finally:
1398 IsUpper = bUpper
1399 SF_Utils._ExitFunction(cstThisSub)
1400 Exit Function
1401 Catch:
1402 GoTo Finally
1403 End Function &apos; ScriptForge.SF_String.IsUpper
1405 REM -----------------------------------------------------------------------------
1406 Public Function IsUrl(Optional ByRef InputStr As Variant) As Boolean
1407 &apos;&apos;&apos; Return True if the string is a valid absolute URL (Uniform Resource Locator)
1408 &apos;&apos;&apos; The parsing is done by the ParseStrict method of the URLTransformer UNO service
1409 &apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XURLTransformer.html
1410 &apos;&apos;&apos; Args:
1411 &apos;&apos;&apos; InputStr: the input string
1412 &apos;&apos;&apos; Returns:
1413 &apos;&apos;&apos; True if the string contains a URL and there is at least one character, False otherwise
1414 &apos;&apos;&apos; Examples:
1415 &apos;&apos;&apos; SF_String.IsUrl(&quot;http://foo.bar/?q=Test%20URL-encoded%20stuff&quot;) returns True
1417 Dim bUrl As Boolean &apos; Return value
1418 Const cstThisSub = &quot;String.IsUrl&quot;
1419 Const cstSubArgs = &quot;InputStr&quot;
1421 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1422 bUrl = False
1424 Check:
1425 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1426 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1427 End If
1429 Try:
1430 If Len(InputStr) &gt; 0 Then bUrl = ( Len(SF_FileSystem._ParseUrl(InputStr).Main) &gt; 0 )
1432 Finally:
1433 IsUrl = bUrl
1434 SF_Utils._ExitFunction(cstThisSub)
1435 Exit Function
1436 Catch:
1437 GoTo Finally
1438 End Function &apos; ScriptForge.SF_String.IsUrl
1440 REM -----------------------------------------------------------------------------
1441 Public Function IsWhitespace(Optional ByRef InputStr As Variant) As Boolean
1442 &apos;&apos;&apos; Return True if all characters in the string are whitespaces
1443 &apos;&apos;&apos; Whitespaces include Space(32), HT(9), LF(10), VT(11), FF(12), CR(13), Next Line(133), No-break space(160),
1444 &apos;&apos;&apos; Line separator(8232), Paragraph separator(8233)
1445 &apos;&apos;&apos; Args:
1446 &apos;&apos;&apos; InputStr: the input string
1447 &apos;&apos;&apos; Returns:
1448 &apos;&apos;&apos; True if the string contains only whitespaces and there is at least one character, False otherwise
1449 &apos;&apos;&apos; Examples:
1450 &apos;&apos;&apos; SF_String.IsWhitespace(&quot; &quot; &amp; Chr(9) &amp; Chr(10)) returns True
1452 Dim bWhitespace As Boolean &apos; Return value
1453 Const cstThisSub = &quot;String.IsWhitespace&quot;
1454 Const cstSubArgs = &quot;InputStr&quot;
1456 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1457 bWhitespace = False
1459 Check:
1460 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1461 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1462 End If
1464 Try:
1465 If Len(InputStr) &gt; 0 Then bWhitespace = SF_String.IsRegex(InputStr, REGEXWHITESPACES, CaseSensitive := False)
1467 Finally:
1468 IsWhitespace = bWhitespace
1469 SF_Utils._ExitFunction(cstThisSub)
1470 Exit Function
1471 Catch:
1472 GoTo Finally
1473 End Function &apos; ScriptForge.SF_String.IsWhitespace
1475 REM -----------------------------------------------------------------------------
1476 Public Function JustifyCenter(Optional ByRef InputStr As Variant _
1477 , Optional ByVal Length As Variant _
1478 , Optional ByVal Padding As Variant _
1479 ) As String
1480 &apos;&apos;&apos; Return the input string center justified
1481 &apos;&apos;&apos; Args:
1482 &apos;&apos;&apos; InputStr: the input string
1483 &apos;&apos;&apos; Length: the resulting string length (default = length of input string)
1484 &apos;&apos;&apos; Padding: the padding (single) character (default = the ascii space)
1485 &apos;&apos;&apos; Returns:
1486 &apos;&apos;&apos; The input string without its leading and trailing white spaces
1487 &apos;&apos;&apos; completed left and right up to a total length of Length with the character Padding
1488 &apos;&apos;&apos; If the input string is empty, the returned string is empty too
1489 &apos;&apos;&apos; If the requested length is shorter than the center justified input string,
1490 &apos;&apos;&apos; then the returned string is truncated
1491 &apos;&apos;&apos; Examples:
1492 &apos;&apos;&apos; SF_String.JustifyCenter(&quot; ABCDE &quot;, Padding := &quot;x&quot;) returns &quot;xxABCDEFxx&quot;
1494 Dim sJustify As String &apos; Return value
1495 Dim lLength As Long &apos; Length of input string
1496 Dim lJustLength As Long &apos; Length of trimmed input string
1497 Dim sPadding As String &apos; Series of Padding characters
1498 Const cstThisSub = &quot;String.JustifyCenter&quot;
1499 Const cstSubArgs = &quot;InputStr, [length=Len(InputStr)], [Padding=&quot;&quot; &quot;&quot;]&quot;
1501 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1502 sJustify = &quot;&quot;
1504 Check:
1505 If IsMissing(Length) Or IsEmpty(Length) Then Length = 0
1506 If IsMissing(Padding) Or IsMissing(Padding) Then Padding = &quot; &quot;
1507 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1508 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1509 If Not SF_Utils._Validate(Length, &quot;Length&quot;, V_NUMERIC) Then GoTo Finally
1510 If Not SF_Utils._Validate(Padding, &quot;Padding&quot;, V_STRING) Then GoTo Finally
1511 End If
1512 If Len(Padding) = 0 Then Padding = &quot; &quot; Else Padding = Left(Padding, 1)
1514 Try:
1515 lLength = Len(InputStr)
1516 If Length = 0 Then Length = lLength
1517 If lLength &gt; 0 Then
1518 sJustify = SF_String.TrimExt(InputStr) &apos; Trim left and right
1519 lJustLength = Len(sJustify)
1520 If lJustLength &gt; Length Then
1521 sJustify = Mid(sJustify, Int((lJustLength - Length) / 2) + 1, Length)
1522 ElseIf lJustLength &lt; Length Then
1523 sPadding = String(Int((Length - lJustLength) / 2), Padding)
1524 sJustify = sPadding &amp; sJustify &amp; sPadding
1525 If Len(sJustify) &lt; Length Then sJustify = sJustify &amp; Padding &apos; One Padding char is lacking when lJustLength is odd
1526 End If
1527 End If
1529 Finally:
1530 JustifyCenter = sJustify
1531 SF_Utils._ExitFunction(cstThisSub)
1532 Exit Function
1533 Catch:
1534 GoTo Finally
1535 End Function &apos; ScriptForge.SF_String.JustifyCenter
1537 REM -----------------------------------------------------------------------------
1538 Public Function JustifyLeft(Optional ByRef InputStr As Variant _
1539 , Optional ByVal Length As Variant _
1540 , Optional ByVal Padding As Variant _
1541 ) As String
1542 &apos;&apos;&apos; Return the input string left justified
1543 &apos;&apos;&apos; Args:
1544 &apos;&apos;&apos; InputStr: the input string
1545 &apos;&apos;&apos; Length: the resulting string length (default = length of input string)
1546 &apos;&apos;&apos; Padding: the padding (single) character (default = the ascii space)
1547 &apos;&apos;&apos; Returns:
1548 &apos;&apos;&apos; The input string without its leading white spaces
1549 &apos;&apos;&apos; filled up to a total length of Length with the character Padding
1550 &apos;&apos;&apos; If the input string is empty, the returned string is empty too
1551 &apos;&apos;&apos; If the requested length is shorter than the left justified input string,
1552 &apos;&apos;&apos; then the returned string is truncated
1553 &apos;&apos;&apos; Examples:
1554 &apos;&apos;&apos; SF_String.JustifyLeft(&quot; ABCDE &quot;, Padding := &quot;x&quot;) returns &quot;ABCDE xxx&quot;
1556 Dim sJustify As String &apos; Return value
1557 Dim lLength As Long &apos; Length of input string
1558 Const cstThisSub = &quot;String.JustifyLeft&quot;
1559 Const cstSubArgs = &quot;InputStr, [length=Len(InputStr)], [Padding=&quot;&quot; &quot;&quot;]&quot;
1561 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1562 sJustify = &quot;&quot;
1564 Check:
1565 If IsMissing(Length) Or IsEmpty(Length) Then Length = 0
1566 If IsMissing(Padding) Or IsMissing(Padding) Then Padding = &quot; &quot;
1567 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1568 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1569 If Not SF_Utils._Validate(Length, &quot;Length&quot;, V_NUMERIC) Then GoTo Finally
1570 If Not SF_Utils._Validate(Padding, &quot;Padding&quot;, V_STRING) Then GoTo Finally
1571 End If
1572 If Len(Padding) = 0 Then Padding = &quot; &quot; Else Padding = Left(Padding, 1)
1574 Try:
1575 lLength = Len(InputStr)
1576 If Length = 0 Then Length = lLength
1577 If lLength &gt; 0 Then
1578 sJustify = SF_String.ReplaceRegex(InputStr, REGEXLTRIM, &quot;&quot;) &apos; Trim left
1579 If Len(sJustify) &gt;= Length Then
1580 sJustify = Left(sJustify, Length)
1581 Else
1582 sJustify = sJustify &amp; String(Length - Len(sJustify), Padding)
1583 End If
1584 End If
1586 Finally:
1587 JustifyLeft = sJustify
1588 SF_Utils._ExitFunction(cstThisSub)
1589 Exit Function
1590 Catch:
1591 GoTo Finally
1592 End Function &apos; ScriptForge.SF_String.JustifyLeft
1594 REM -----------------------------------------------------------------------------
1595 Public Function JustifyRight(Optional ByRef InputStr As Variant _
1596 , Optional ByVal Length As Variant _
1597 , Optional ByVal Padding As Variant _
1598 ) As String
1599 &apos;&apos;&apos; Return the input string right justified
1600 &apos;&apos;&apos; Args:
1601 &apos;&apos;&apos; InputStr: the input string
1602 &apos;&apos;&apos; Length: the resulting string length (default = length of input string)
1603 &apos;&apos;&apos; Padding: the padding (single) character (default = the ascii space)
1604 &apos;&apos;&apos; Returns:
1605 &apos;&apos;&apos; The input string without its trailing white spaces
1606 &apos;&apos;&apos; preceded up to a total length of Length with the character Padding
1607 &apos;&apos;&apos; If the input string is empty, the returned string is empty too
1608 &apos;&apos;&apos; If the requested length is shorter than the right justified input string,
1609 &apos;&apos;&apos; then the returned string is right-truncated
1610 &apos;&apos;&apos; Examples:
1611 &apos;&apos;&apos; SF_String.JustifyRight(&quot; ABCDE &quot;, Padding := &quot;x&quot;) returns &quot;x ABCDE&quot;
1613 Dim sJustify As String &apos; Return value
1614 Dim lLength As Long &apos; Length of input string
1615 Const cstThisSub = &quot;String.JustifyRight&quot;
1616 Const cstSubArgs = &quot;InputStr, [length=Len(InputStr)], [Padding=&quot;&quot; &quot;&quot;]&quot;
1618 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1619 sJustify = &quot;&quot;
1621 Check:
1622 If IsMissing(Length) Or IsEmpty(Length) Then Length = 0
1623 If IsMissing(Padding) Or IsMissing(Padding) Then Padding = &quot; &quot;
1624 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1625 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1626 If Not SF_Utils._Validate(Length, &quot;Length&quot;, V_NUMERIC) Then GoTo Finally
1627 If Not SF_Utils._Validate(Padding, &quot;Padding&quot;, V_STRING) Then GoTo Finally
1628 End If
1629 If Len(Padding) = 0 Then Padding = &quot; &quot; Else Padding = Left(Padding, 1)
1631 Try:
1632 lLength = Len(InputStr)
1633 If Length = 0 Then Length = lLength
1634 If lLength &gt; 0 Then
1635 sJustify = SF_String.ReplaceRegex(InputStr, REGEXRTRIM, &quot;&quot;) &apos; Trim right
1636 If Len(sJustify) &gt;= Length Then
1637 sJustify = Right(sJustify, Length)
1638 Else
1639 sJustify = String(Length - Len(sJustify), Padding) &amp; sJustify
1640 End If
1641 End If
1643 Finally:
1644 JustifyRight = sJustify
1645 SF_Utils._ExitFunction(cstThisSub)
1646 Exit Function
1647 Catch:
1648 GoTo Finally
1649 End Function &apos; ScriptForge.SF_String.JustifyRight
1651 REM -----------------------------------------------------------------------------
1652 Public Function Methods() As Variant
1653 &apos;&apos;&apos; Return the list of public methods of the String service as an array
1655 Methods = Array( _
1656 &quot;Capitalize&quot; _
1657 , &quot;Count&quot; _
1658 , &quot;EndWith&quot; _
1659 , &quot;Escape&quot; _
1660 , &quot;ExpandTabs&quot; _
1661 , &quot;FilterNotPrintable&quot; _
1662 , &quot;FindRegex&quot; _
1663 , &quot;HashStr&quot; _
1664 , &quot;HtmlEncode&quot; _
1665 , &quot;IsADate&quot; _
1666 , &quot;IsAlpha&quot; _
1667 , &quot;IsAlphaNum&quot; _
1668 , &quot;IsAscii&quot; _
1669 , &quot;IsDigit&quot; _
1670 , &quot;IsEmail&quot; _
1671 , &quot;IsFileName&quot; _
1672 , &quot;IsHexDigit&quot; _
1673 , &quot;IsIPv4&quot; _
1674 , &quot;IsLike&quot; _
1675 , &quot;IsLower&quot; _
1676 , &quot;IsPrintable&quot; _
1677 , &quot;IsRegex&quot; _
1678 , &quot;IsSheetName&quot; _
1679 , &quot;IsTitle&quot; _
1680 , &quot;IsUpper&quot; _
1681 , &quot;IsUrl&quot; _
1682 , &quot;IsWhitespace&quot; _
1683 , &quot;JustifyCenter&quot; _
1684 , &quot;JustifyLeft&quot; _
1685 , &quot;JustifyRight&quot; _
1686 , &quot;Quote&quot; _
1687 , &quot;ReplaceChar&quot; _
1688 , &quot;ReplaceRegex&quot; _
1689 , &quot;ReplaceStr&quot; _
1690 , &quot;Represent&quot; _
1691 , &quot;Reverse&quot; _
1692 , &quot;SplitLines&quot; _
1693 , &quot;SplitNotQuoted&quot; _
1694 , &quot;StartsWith&quot; _
1695 , &quot;TrimExt&quot; _
1696 , &quot;Unescape&quot; _
1697 , &quot;Unquote&quot; _
1698 , &quot;Wrap&quot; _
1701 End Function &apos; ScriptForge.SF_String.Methods
1703 REM -----------------------------------------------------------------------------
1704 Public Function Properties() As Variant
1705 &apos;&apos;&apos; Return the list or properties as an array
1707 Properties = Array( _
1708 &quot;sfCR&quot; _
1709 , &quot;sfCRLF&quot; _
1710 , &quot;sfLF&quot; _
1711 , &quot;sfNEWLINE&quot; _
1712 , &quot;sfTAB&quot; _
1715 End Function &apos; ScriptForge.SF_Session.Properties
1717 REM -----------------------------------------------------------------------------
1718 Public Function Quote(Optional ByRef InputStr As Variant _
1719 , Optional ByVal QuoteChar As String _
1720 ) As String
1721 &apos;&apos;&apos; Return the input string surrounded with double quotes
1722 &apos;&apos;&apos; Used f.i. to prepare a string field to be stored in a csv-like file
1723 &apos;&apos;&apos; Args:
1724 &apos;&apos;&apos; InputStr: the input string
1725 &apos;&apos;&apos; QuoteChar: either &quot; (default) or &apos;
1726 &apos;&apos;&apos; Returns:
1727 &apos;&apos;&apos; Existing - including leading and/or trailing - double quotes are doubled
1728 &apos;&apos;&apos; Examples:
1729 &apos;&apos;&apos; SF_String.Quote(&quot;àé&quot;&quot;n ΣlPµ Русский&quot;) returns &quot;&quot;&quot;àé&quot;&quot;&quot;&quot;n ΣlPµ Русский&quot;&quot;&quot;
1731 Dim sQuote As String &apos; Return value
1732 Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
1733 Const cstEscape = &quot;\&quot;
1734 Const cstThisSub = &quot;String.Quote&quot;
1735 Const cstSubArgs = &quot;InputStr&quot;
1737 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1738 sQuote = &quot;&quot;
1740 Check:
1741 If IsMissing(QuoteChar) Or IsEmpty(QuoteChar) Then QuoteChar = cstDouble
1742 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1743 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1744 If Not SF_Utils._Validate(QuoteChar, &quot;QuoteChar&quot;, V_STRING, Array(cstDouble, cstSingle)) Then GoTo Finally
1745 End If
1747 Try:
1748 If QuoteChar = cstDouble Then
1749 sQuote = cstDouble &amp; Replace(InputStr, cstDouble, cstDouble &amp; cstDouble) &amp; cstDouble
1750 Else
1751 sQuote = Replace(InputStr, cstEscape, cstEscape &amp; cstEscape)
1752 sQuote = cstSingle &amp; Replace(sQuote, cstSingle, cstEscape &amp; cstSingle) &amp; cstSingle
1753 End If
1755 Finally:
1756 Quote = sQuote
1757 SF_Utils._ExitFunction(cstThisSub)
1758 Exit Function
1759 Catch:
1760 GoTo Finally
1761 End Function &apos; ScriptForge.SF_String.Quote
1763 REM -----------------------------------------------------------------------------
1764 Public Function ReplaceChar(Optional ByRef InputStr As Variant _
1765 , Optional ByVal Before As Variant _
1766 , Optional ByVal After As Variant _
1767 ) As String
1768 &apos;&apos;&apos; Replace in InputStr all occurrences of any character from Before
1769 &apos;&apos;&apos; by the corresponding character in After
1770 &apos;&apos;&apos; Args:
1771 &apos;&apos;&apos; InputStr: the input string on which replacements should occur
1772 &apos;&apos;&apos; Before: a string of characters to replace 1 by 1 in InputStr
1773 &apos;&apos;&apos; After: the replacing characters
1774 &apos;&apos;&apos; Returns:
1775 &apos;&apos;&apos; The new string after replacement of Nth character of Before by the Nth character of After
1776 &apos;&apos;&apos; Replacements are done one by one =&gt; potential overlaps
1777 &apos;&apos;&apos; If the length of Before is larger than the length of After,
1778 &apos;&apos;&apos; the residual characters of Before are replaced by the last character of After
1779 &apos;&apos;&apos; The input string when Before is the zero-length string
1780 &apos;&apos;&apos; Examples: easily remove accents
1781 &apos;&apos;&apos; SF_String.ReplaceChar(&quot;Protégez votre vie privée&quot;, &quot;àâãçèéêëîïôöûüýÿ&quot;, &quot;aaaceeeeiioouuyy&quot;)
1782 &apos;&apos;&apos; returns &quot;Protegez votre vie privee&quot;
1783 &apos;&apos;&apos; SF_String.ReplaceChar(&quot;Protégez votre vie privée&quot;, SF_String.CHARSWITHACCENT, SF_String.CHARSWITHOUTACCENT)
1785 Dim sOutput As String &apos; Return value
1786 Dim iCaseSensitive As Integer &apos; Always 0 (True)
1787 Dim sBefore As String &apos; A single character extracted from InputStr
1788 Dim sAfter As String &apos; A single character extracted from After
1789 Dim lInStr As Long &apos; Output of InStr()
1790 Dim i As Long
1791 Const cstThisSub = &quot;String.ReplaceChar&quot;
1792 Const cstSubArgs = &quot;InputStr, Before, After&quot;
1794 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1795 sOutput = &quot;&quot;
1797 Check:
1798 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1799 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1800 If Not SF_Utils._Validate(Before, &quot;Before&quot;, V_STRING) Then GoTo Finally
1801 If Not SF_Utils._Validate(After, &quot;After&quot;, V_STRING) Then GoTo Finally
1802 End If
1804 Try:
1805 &apos; Replace standard function =&gt; Replace(string, before, after, start, occurrences, casesensitive)
1806 sOutput = InputStr
1807 iCaseSensitive = 0
1809 &apos; Replace one by one up length of Before and After
1810 If Len(Before) &gt; 0 Then
1811 i = 1
1812 Do While i &lt;= Len(sOutput)
1813 sBefore = Mid(sOutput, i, 1)
1814 lInStr = InStr(1, Before, sBefore, iCaseSensitive)
1815 If lInStr &gt; 0 Then
1816 If Len(After) = 0 Then
1817 sAfter = &quot;&quot;
1818 ElseIf lInStr &gt; Len(After) Then
1819 sAfter = Right(After, 1)
1820 Else
1821 sAfter = Mid(After, lInStr, 1)
1822 End If
1823 sOutput = Left(sOutput, i - 1) &amp; Replace(sOutput, sBefore, sAfter, i, Empty, iCaseSensitive)
1824 End If
1825 i = i + 1
1826 Loop
1827 End If
1829 Finally:
1830 ReplaceChar = sOutput
1831 SF_Utils._ExitFunction(cstThisSub)
1832 Exit Function
1833 Catch:
1834 GoTo Finally
1835 End Function &apos; ScriptForge.SF_String.ReplaceChar
1837 REM -----------------------------------------------------------------------------
1838 Public Function ReplaceRegex(Optional ByRef InputStr As Variant _
1839 , Optional ByVal Regex As Variant _
1840 , Optional ByRef NewStr As Variant _
1841 , Optional ByVal CaseSensitive As Variant _
1842 ) As String
1843 &apos;&apos;&apos; Replace in InputStr all occurrences of a given regular expression by NewStr
1844 &apos;&apos;&apos; Args:
1845 &apos;&apos;&apos; InputStr: the input string where replacements should occur
1846 &apos;&apos;&apos; Regex: the regular expression
1847 &apos;&apos;&apos; NewStr: the replacing string
1848 &apos;&apos;&apos; CaseSensitive: default = False
1849 &apos;&apos;&apos; Returns:
1850 &apos;&apos;&apos; The new string after all replacements
1851 &apos;&apos;&apos; Examples:
1852 &apos;&apos;&apos; SF_String.ReplaceRegex(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;[a-z]&quot;, &quot;x&quot;, CaseSensitive := True)
1853 &apos;&apos;&apos; returns &quot;Lxxxx xxxxx xxxxx xxx xxxx, xxxxxxxxxxx xxxxxxxxxx xxxx.&quot;
1854 &apos;&apos;&apos; SF_String.ReplaceRegex(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;\b[a-z]+\b&quot;, &quot;x&quot;, CaseSensitive := False)
1855 &apos;&apos;&apos; returns &quot;x x x x x, x x x.&quot; (each word is replaced by x)
1858 Dim sOutput As String &apos; Return value
1859 Dim lStartOld As Long &apos; Previous start of search
1860 Dim lStartNew As Long &apos; Next start of search
1861 Dim sSubstring As String &apos; Substring to replace
1862 Const cstThisSub = &quot;String.ReplaceRegex&quot;
1863 Const cstSubArgs = &quot;InputStr, Regex, NewStr, [CaseSensitive=False]&quot;
1865 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1866 sOutput = &quot;&quot;
1868 Check:
1869 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
1870 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1871 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1872 If Not SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Finally
1873 If Not SF_Utils._Validate(NewStr, &quot;NewStr&quot;, V_STRING) Then GoTo Finally
1874 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
1875 End If
1877 Try:
1878 sOutput = &quot;&quot;
1879 lStartNew = 1
1880 lStartOld = 1
1882 Do While lStartNew &gt;= 1 And lStartNew &lt;= Len(InputStr)
1883 sSubstring = SF_String.FindRegex(InputStr, Regex, lStartNew, CaseSensitive)
1884 If lStartNew = 0 Then &apos; Regex not found
1885 &apos; Copy remaining substring of InputStr before leaving
1886 sOutput = sOutput &amp; Mid(InputStr, lStartOld)
1887 Exit Do
1888 End If
1889 &apos; Append the interval between 2 occurrences and the replacing string
1890 If lStartNew &gt; lStartOld Then sOutput = sOutput &amp; Mid(InputStr, lStartOld, lStartNew - lStartOld)
1891 sOutput = sOutput &amp; NewStr
1892 lStartOld = lStartNew + Len(sSubstring)
1893 lStartNew = lStartOld
1894 Loop
1896 Finally:
1897 ReplaceRegex = sOutput
1898 SF_Utils._ExitFunction(cstThisSub)
1899 Exit Function
1900 Catch:
1901 GoTo Finally
1902 End Function &apos; ScriptForge.SF_String.ReplaceRegex
1904 REM -----------------------------------------------------------------------------
1905 Public Function ReplaceStr(Optional ByRef InputStr As Variant _
1906 , Optional ByVal OldStr As Variant _
1907 , Optional ByVal NewStr As Variant _
1908 , Optional ByVal Occurrences As Variant _
1909 , Optional ByVal CaseSensitive As Variant _
1910 ) As String
1911 &apos;&apos;&apos; Replace in InputStr some or all occurrences of OldStr by NewStr
1912 &apos;&apos;&apos; Args:
1913 &apos;&apos;&apos; InputStr: the input string on which replacements should occur
1914 &apos;&apos;&apos; OldStr: the string to replace or a 1D array of strings to replace
1915 &apos;&apos;&apos; Zero-length strings are ignored
1916 &apos;&apos;&apos; NewStr: the replacing string or a 1D array of replacing strings
1917 &apos;&apos;&apos; If OldStr is an array
1918 &apos;&apos;&apos; each occurrence of any of the items of OldStr is replaced by NewStr
1919 &apos;&apos;&apos; If OldStr and NewStr are arrays
1920 &apos;&apos;&apos; replacements occur one by one up to the UBound of NewStr
1921 &apos;&apos;&apos; remaining OldStr(ings) are replaced by the last element of NewStr
1922 &apos;&apos;&apos; Occurrences: the maximum number of replacements (0, default, = all occurrences)
1923 &apos;&apos;&apos; Is applied for each single replacement when OldStr is an array
1924 &apos;&apos;&apos; CaseSensitive: True or False (default)
1925 &apos;&apos;&apos; Returns:
1926 &apos;&apos;&apos; The new string after replacements
1927 &apos;&apos;&apos; Replacements are done one by one when OldStr is an array =&gt; potential overlaps
1928 &apos;&apos;&apos; Examples:
1929 &apos;&apos;&apos; SF_String.ReplaceStr(&quot;abCcdefghHij&quot;, Array(&quot;c&quot;, &quot;h&quot;), Array(&quot;Y&quot;, &quot;Z&quot;), CaseSensitive := False) returns &quot;abYYdefgZZij&quot;
1931 Dim sOutput As String &apos; Return value
1932 Dim iCaseSensitive As Integer &apos; Integer alias for boolean CaseSensitive
1933 Dim vOccurrences As Variant &apos; Variant alias for Integer Occurrences
1934 Dim sNewStr As String &apos; Alias for a NewStr item
1935 Dim i As Long, j As Long
1936 Const cstThisSub = &quot;String.ReplaceStr&quot;
1937 Const cstSubArgs = &quot;InputStr, OldStr, NewStr, [Occurrences=0], [CaseSensitive=False]&quot;
1939 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1940 sOutput = &quot;&quot;
1942 Check:
1943 If IsMissing(Occurrences) Or IsEmpty(Occurrences) Then Occurrences = 0
1944 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
1945 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1946 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
1947 If IsArray(OldStr) Then
1948 If Not SF_Utils._ValidateArray(OldStr, &quot;OldStr&quot;, 1, V_STRING, True) Then GoTo Finally
1949 Else
1950 If Not SF_Utils._Validate(OldStr, &quot;OldStr&quot;, V_STRING) Then GoTo Finally
1951 End If
1952 If IsArray(NewStr) Then
1953 If Not SF_Utils._ValidateArray(NewStr, &quot;NewStr&quot;, 1, V_STRING, True) Then GoTo Finally
1954 Else
1955 If Not SF_Utils._Validate(NewStr, &quot;NewStr&quot;, V_STRING) Then GoTo Finally
1956 End If
1957 If Not SF_Utils._Validate(Occurrences, &quot;Occurrences&quot;, V_NUMERIC) Then GoTo Finally
1958 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
1959 End If
1961 Try:
1962 &apos; Replace standard function =&gt; Replace(string, before, after, start, occurrences, casesensitive)
1963 sOutput = InputStr
1964 iCaseSensitive = Iif(CaseSensitive, 0, 1) &apos; 1 = False ;)
1965 vOccurrences = Iif(Occurrences = 0, Empty, Occurrences) &apos; Empty = no limit
1966 If Not IsArray(OldStr) Then OldStr = Array(OldStr)
1967 If Not IsArray(NewStr) Then NewStr = Array(NewStr)
1969 &apos; Replace one by one up to UBounds of Old and NewStr
1970 j = LBound(NewStr) - 1
1971 For i = LBound(OldStr) To UBound(OldStr)
1972 j = j + 1
1973 If j &lt;= UBound(NewStr) Then sNewStr = NewStr(j) &apos; Else do not change
1974 If StrComp(OldStr(i), sNewStr, 1) &lt;&gt; 0 Then
1975 sOutput = Replace(sOutput, OldStr(i), sNewStr, 1, vOccurrences, iCaseSensitive)
1976 End If
1977 Next i
1979 Finally:
1980 ReplaceStr = sOutput
1981 SF_Utils._ExitFunction(cstThisSub)
1982 Exit Function
1983 Catch:
1984 GoTo Finally
1985 End Function &apos; ScriptForge.SF_String.ReplaceStr
1987 REM -----------------------------------------------------------------------------
1988 Public Function Represent(Optional ByRef AnyValue As Variant _
1989 , Optional ByVal MaxLength As Variant _
1990 ) As String
1991 &apos;&apos;&apos; Return a readable (string) form of the argument, truncated at MaxLength
1992 &apos;&apos;&apos; Args:
1993 &apos;&apos;&apos; AnyValue: really any value (object, date, whatever)
1994 &apos;&apos;&apos; MaxLength: the maximum length of the resulting string (Default = 0, unlimited)
1995 &apos;&apos;&apos; Returns:
1996 &apos;&apos;&apos; The argument converted or transformed into a string of a maximum length = MaxLength
1997 &apos;&apos;&apos; Objects are surrounded with square brackets ([])
1998 &apos;&apos;&apos; In strings, tabs and line breaks are replaced by \t, \n or \r
1999 &apos;&apos;&apos; If the effective length exceeds MaxLength, the final part of the string is replaced by &quot; ... (N)&quot;
2000 &apos;&apos;&apos; where N = the total length of the string before truncation
2001 &apos;&apos;&apos; Examples:
2002 &apos;&apos;&apos; SF_String.Represent(&quot;this is a usual string&quot;) returns &quot;this is a usual string&quot;
2003 &apos;&apos;&apos; SF_String.Represent(&quot;this is a usual string&quot;, 15) returns &quot;this i ... (22)&quot;
2004 &apos;&apos;&apos; SF_String.Represent(&quot;this is a&quot; &amp; Chr(10) &amp; &quot; 2-lines string&quot;) returns &quot;this is a\n 2-lines string&quot;
2005 &apos;&apos;&apos; SF_String.Represent(Empty) returns &quot;[EMPTY]&quot;
2006 &apos;&apos;&apos; SF_String.Represent(Null) returns &quot;[NULL]&quot;
2007 &apos;&apos;&apos; SF_String.Represent(Pi) returns &quot;3.142&quot;
2008 &apos;&apos;&apos; SF_String.Represent(CreateUnoService(&quot;com.sun.star.util.PathSettings&quot;)) returns &quot;[com.sun.star.comp.framework.PathSettings]&quot;
2009 &apos;&apos;&apos; SF_String.Represent(Array(1, 2, &quot;Text&quot; &amp; Chr(9) &amp; &quot;here&quot;)) returns &quot;[ARRAY] (0:2) (1, 2, Text\there)&quot;
2010 &apos;&apos;&apos; Dim myDict As Variant : myDict = CreateScriptService(&quot;Dictionary&quot;)
2011 &apos;&apos;&apos; myDict.Add(&quot;A&quot;, 1) : myDict.Add(&quot;B&quot;, 2)
2012 &apos;&apos;&apos; SF_String.Represent(myDict) returns &quot;[Dictionary] (&quot;A&quot;:1, &quot;B&quot;:2)&quot;
2014 Dim sRepr As String &apos; Return value
2015 Const cstThisSub = &quot;String.Represent&quot;
2016 Const cstSubArgs = &quot;AnyValue, [MaxLength=0]&quot;
2018 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2019 sRepr = &quot;&quot;
2021 Check:
2022 If IsMissing(AnyValue) Then AnyValue = Empty
2023 If IsMissing(MaxLength) Or IsEmpty(MaxLength) Then MaxLength = 0
2024 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2025 If Not SF_Utils._Validate(MaxLength, &quot;MaxLength&quot;, V_NUMERIC) Then GoTo Finally
2026 End If
2028 Try:
2029 sRepr = SF_Utils._Repr(AnyValue, MaxLength)
2030 If MaxLength &gt; 0 And MaxLength &lt; Len(sRepr) Then sRepr = sRepr &amp; &quot; ... (&quot; &amp; Len(sRepr) &amp; &quot;)&quot;
2032 Finally:
2033 Represent = sRepr
2034 SF_Utils._ExitFunction(cstThisSub)
2035 Exit Function
2036 Catch:
2037 GoTo Finally
2038 End Function &apos; ScriptForge.SF_String.Represent
2040 REM -----------------------------------------------------------------------------
2041 Public Function Reverse(Optional ByRef InputStr As Variant) As String
2042 &apos;&apos;&apos; Return the input string in reversed order
2043 &apos;&apos;&apos; It is equivalent to the standard StrReverse Basic function
2044 &apos;&apos;&apos; The latter requires the OpTion VBASupport 1 statement to be present in the module
2045 &apos;&apos;&apos; Args:
2046 &apos;&apos;&apos; InputStr: the input string
2047 &apos;&apos;&apos; Returns:
2048 &apos;&apos;&apos; The input string in reversed order
2049 &apos;&apos;&apos; Examples:
2050 &apos;&apos;&apos; SF_String.Reverse(&quot;abcdefghij&quot;) returns &quot;jihgfedcba&quot;
2052 Dim sReversed As String &apos; Return value
2053 Dim lLength As Long &apos; Length of input string
2054 Dim i As Long
2055 Const cstThisSub = &quot;String.Reverse&quot;
2056 Const cstSubArgs = &quot;InputSt&quot;
2058 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2059 sReversed = &quot;&quot;
2061 Check:
2062 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2063 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2064 End If
2066 Try:
2067 lLength = Len(InputStr)
2068 If lLength &gt; 0 Then
2069 sReversed = Space(lLength)
2070 For i = 1 To lLength
2071 Mid(sReversed, i, 1) = Mid(InputStr, lLength - i + 1)
2072 Next i
2073 End If
2075 Finally:
2076 Reverse = sReversed
2077 SF_Utils._ExitFunction(cstThisSub)
2078 Exit Function
2079 Catch:
2080 GoTo Finally
2081 End Function &apos; ScriptForge.SF_String.Reverse
2083 REM -----------------------------------------------------------------------------
2084 Public Function SetProperty(Optional ByVal PropertyName As Variant _
2085 , Optional ByRef Value As Variant _
2086 ) As Boolean
2087 &apos;&apos;&apos; Set a new value to the given property
2088 &apos;&apos;&apos; Args:
2089 &apos;&apos;&apos; PropertyName: the name of the property as a string
2090 &apos;&apos;&apos; Value: its new value
2091 &apos;&apos;&apos; Exceptions
2092 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
2094 Const cstThisSub = &quot;String.SetProperty&quot;
2095 Const cstSubArgs = &quot;PropertyName, Value&quot;
2097 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2098 SetProperty = False
2100 Check:
2101 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2102 If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
2103 End If
2105 Try:
2106 Select Case UCase(PropertyName)
2107 Case Else
2108 End Select
2110 Finally:
2111 SF_Utils._ExitFunction(cstThisSub)
2112 Exit Function
2113 Catch:
2114 GoTo Finally
2115 End Function &apos; ScriptForge.SF_String.SetProperty
2117 REM -----------------------------------------------------------------------------
2118 Public Function SplitLines(Optional ByRef InputStr As Variant _
2119 , Optional ByVal KeepBreaks As Variant _
2120 ) As Variant
2121 &apos;&apos;&apos; Return an array of the lines in a string, breaking at line boundaries
2122 &apos;&apos;&apos; Line boundaries include LF(10), VT(12), CR(13), LF+CR, File separator(28), Group separator(29), Record separator(30),
2123 &apos;&apos;&apos; Next Line(133), Line separator(8232), Paragraph separator(8233)
2124 &apos;&apos;&apos; Args:
2125 &apos;&apos;&apos; InputStr: the input string
2126 &apos;&apos;&apos; KeepBreaks: when True, line breaks are preserved in the output array (default = False)
2127 &apos;&apos;&apos; Returns:
2128 &apos;&apos;&apos; An array of all the individual lines
2129 &apos;&apos;&apos; Examples:
2130 &apos;&apos;&apos; SF_String.SplitLines(&quot;Line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot; &amp; Chr(13) &amp; &quot;Line3&quot;) returns (&quot;Line1&quot;, &quot;Line2&quot;, &quot;Line3&quot;)
2131 &apos;&apos;&apos; SF_String.SplitLines(&quot;Line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot; &amp; Chr(13) &amp; &quot;Line3&quot; &amp; Chr(10)) returns (&quot;Line1&quot;, &quot;Line2&quot;, &quot;Line3&quot;, &quot;&quot;)
2133 Dim vSplit As Variant &apos; Return value
2134 Dim vLineBreaks As Variant &apos; Array of recognized line breaks
2135 Dim vTokenizedBreaks As Variant &apos; Array of line breaks extended with tokens
2136 Dim sAlias As String &apos; Alias for input string
2137 &apos; The procedure uses (dirty) placeholders to identify line breaks
2138 &apos; The used tokens are presumed unlikely present in text strings
2139 Dim sTokenCRLF As String &apos; Token to identify combined CR + LF
2140 Dim sToken As String &apos; Token to identify any line break
2141 Dim i As Long
2142 Const cstThisSub = &quot;String.SplitLines&quot;
2143 Const cstSubArgs = &quot;InputStr, [KeepBreaks=False]&quot;
2145 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2146 vSplit = Array()
2148 Check:
2149 If IsMissing(KeepBreaks) Or IsEmpty(KeepBreaks) Then KeepBreaks = False
2150 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2151 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2152 If Not SF_Utils._Validate(KeepBreaks, &quot;KeepBreaks&quot;, V_BOOLEAN) Then GoTo Finally
2153 End If
2155 Try:
2156 &apos; In next list CR + LF must precede CR and LF
2157 vLineBreaks = Array(SF_String.sfCRLF, SF_String.sfLF, Chr(12), SF_String.sfCR _
2158 , Chr(28), Chr(29), Chr(30), Chr(133), Chr(8232), Chr(8233))
2160 If KeepBreaks = False Then
2161 &apos; Replace line breaks by linefeeds and split on linefeeds
2162 vSplit = Split(SF_String.ReplaceStr(InputStr, vLineBreaks, SF_String.sfLF, CaseSensitive := False), SF_String.sfLF)
2163 Else
2164 sTokenCRLF = Chr(1) &amp; &quot;$&quot; &amp; Chr(2) &amp; &quot;*&quot; &amp; Chr(3) &amp; &quot;$&quot; &amp; Chr(1)
2165 sToken = Chr(1) &amp; &quot;$&quot; &amp; Chr(2) &amp; &quot;*&quot; &amp; Chr(3) &amp; &quot;$&quot; &amp; Chr(2)
2166 vTokenizedBreaks = Array() : ReDim vTokenizedBreaks(0 To UBound(vLineBreaks))
2167 &apos; Extend breaks with token
2168 For i = 0 To UBound(vLineBreaks)
2169 vTokenizedBreaks(i) = Iif(i = 0, sTokenCRLF, vLineBreaks(i)) &amp; sToken
2170 Next i
2171 sAlias = SF_String.ReplaceStr(InputStr, vLineBreaks, vTokenizedBreaks, CaseSensitive := False)
2172 &apos; Suppress CRLF tokens and split
2173 vSplit = Split(Replace(sAlias, sTokenCRLF, SF_String.sfCRLF), sToken)
2174 End If
2176 Finally:
2177 SplitLines = vSplit
2178 SF_Utils._ExitFunction(cstThisSub)
2179 Exit Function
2180 Catch:
2181 GoTo Finally
2182 End Function &apos; ScriptForge.SF_String.SplitLines
2184 REM -----------------------------------------------------------------------------
2185 Public Function SplitNotQuoted(Optional ByRef InputStr As Variant _
2186 , Optional ByVal Delimiter As Variant _
2187 , Optional ByVal Occurrences As Variant _
2188 , Optional ByVal QuoteChar As Variant _
2189 ) As Variant
2190 &apos;&apos;&apos; Split a string on Delimiter into an array. If Delimiter is part of a quoted (sub)string, it is ignored
2191 &apos;&apos;&apos; (used f.i. for parsing of csv-like records)
2192 &apos;&apos;&apos; Args:
2193 &apos;&apos;&apos; InputStr: the input string
2194 &apos;&apos;&apos; Might contain quoted substrings:
2195 &apos;&apos;&apos; The quoting character must be the double quote (&quot;)
2196 &apos;&apos;&apos; To preserve a quoting character inside the quoted substring, use (\) or (&quot;) as escape character
2197 &apos;&apos;&apos; =&gt; [str\&quot;i&quot;&quot;ng] means [str&quot;i&quot;ng]
2198 &apos;&apos;&apos; Delimiter: A string of one or more characters that is used to delimit the input string
2199 &apos;&apos;&apos; The default is the space character
2200 &apos;&apos;&apos; Occurrences: The number of substrings to return (Default = 0, meaning no limit)
2201 &apos;&apos;&apos; QuoteChar: The quoting character, either &quot; (default) or &apos;
2202 &apos;&apos;&apos; Returns:
2203 &apos;&apos;&apos; An array whose items are chunks of the input string, Delimiter not included
2204 &apos;&apos;&apos; Examples:
2205 &apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc def ghi&quot;) returns (&quot;abc&quot;, &quot;def&quot;, &quot;ghi&quot;)
2206 &apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc,&quot;&quot;def,ghi&quot;&quot;&quot;, &quot;,&quot;) returns (&quot;abc&quot;, &quot;&quot;&quot;def,ghi&quot;&quot;&quot;)
2207 &apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc,&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;, &quot;,&quot;) returns (&quot;abc&quot;, &quot;&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;)
2208 &apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc,&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;&quot;,&quot;, &quot;,&quot;) returns (&quot;abc&quot;, &quot;&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;, &quot;&quot;)
2210 Dim vSplit As Variant &apos; Return value
2211 Dim lDelimLen As Long &apos; Length of Delimiter
2212 Dim vStart As Variant &apos; Array of start positions of quoted strings
2213 Dim vEnd As Variant &apos; Array of end positions of quoted strings
2214 Dim lInStr As Long &apos; InStr() on input string
2215 Dim lInStrPrev As Long &apos; Previous value of lInputStr
2216 Dim lBound As Long &apos; UBound of vStart and vEnd
2217 Dim lMin As Long &apos; Lower bound to consider when searching vStart and vEnd
2218 Dim oCharacterClass As Object &apos; com.sun.star.i18n.CharacterClassification
2219 Dim oLocale As Object &apos; com.sun.star.lang.Locale
2220 Dim oParse As Object &apos; com.sun.star.i18n.ParseResult
2221 Dim sChunk As String &apos; Substring of InputStr
2222 Dim bSplit As Boolean &apos; New chunk found or not
2223 Dim i As Long
2224 Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
2225 Const cstThisSub = &quot;String.SplitNotQuoted&quot;
2226 Const cstSubArgs = &quot;InputStr, [Delimiter=&quot;&quot; &quot;&quot;], [Occurrences=0], [QuoteChar=&quot;&quot;&quot; &amp; cstDouble &amp; &quot;&quot;&quot;&quot;
2228 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2229 vSplit = Array()
2231 Check:
2232 If IsMissing(Delimiter) Or IsEmpty(Delimiter) Then Delimiter = &quot; &quot;
2233 If IsMissing(Occurrences) Or IsEmpty(Occurrences) Then Occurrences = 0
2234 If IsMissing(QuoteChar) Or IsEmpty(QuoteChar) Then QuoteChar = cstDouble
2235 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2236 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2237 If Not SF_Utils._Validate(Delimiter, &quot;Delimiter&quot;, V_STRING) Then GoTo Finally
2238 If Not SF_Utils._Validate(Occurrences, &quot;Occurrences&quot;, V_NUMERIC) Then GoTo Finally
2239 If Not SF_Utils._Validate(QuoteChar, &quot;QuoteChar&quot;, V_STRING, Array(cstDouble, cstSingle)) Then GoTo Finally
2240 End If
2241 If Len(Delimiter) = 0 Then Delimiter = &quot; &quot;
2243 Try:
2244 If Occurrences = 1 Or InStr(1, InputStr, Delimiter, 0) = 0 Then &apos; No reason to split
2245 vSplit = Array(InputStr)
2246 ElseIf InStr(1, InputStr, QuoteChar, 0) = 0 Then &apos; No reason to make a complex split
2247 If Occurrences &gt; 0 Then vSplit = Split(InputStr, Delimiter, Occurrences) Else vSplit = Split(InputStr, Delimiter)
2248 Else
2249 If Occurrences &lt; 0 Then Occurrences = 0
2250 Set oCharacterClass = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
2251 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
2253 &apos; Build an array of start/end positions of quoted strings containing at least 1x the Delimiter
2254 vStart = Array() : vEnd = Array()
2255 lInStr = InStr(1, InputStr, QuoteChar)
2256 Do While lInStr &gt; 0
2257 lBound = UBound(vStart)
2258 &apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1i18n_1_1XCharacterClassification.html#ad5f1be91fbe86853200391f828d4166b
2259 Set oParse = oCharacterClass.parsePredefinedToken( _
2260 Iif(QuoteChar = cstDouble, com.sun.star.i18n.KParseType.DOUBLE_QUOTE_STRING, com.sun.star.i18n.KParseType.SINGLE_QUOTE_NAME) _
2261 , InputStr, lInStr - 1, oLocale, 0, &quot;&quot;, 0, &quot;&quot;)
2262 If oParse.CharLen &gt; 0 Then &apos; Is parsing successful ?
2263 &apos; Is there some delimiter ?
2264 If InStr(1, oParse.DequotedNameOrString, Delimiter, 0) &gt; 0 Then
2265 vStart = SF_Array.Append(vStart, lInStr + 0)
2266 vEnd = SF_Array.Append(vEnd, lInStr + oParse.CharLen - 1)
2267 End If
2268 lInStr = InStr(lInStr + oParse.CharLen, InputStr, QuoteChar)
2269 Else
2270 lInStr = 0
2271 End If
2272 Loop
2274 lBound = UBound(vStart)
2275 lDelimLen = Len(Delimiter)
2276 If lBound &lt; 0 Then &apos; Usual split is applicable
2277 vSplit = Split(InputStr, Delimiter, Occurrences)
2278 Else
2279 &apos; Split chunk by chunk
2280 lMin = 0
2281 lInStrPrev = 0
2282 lInStr = InStr(1, InputStr, Delimiter, 0)
2283 Do While lInStr &gt; 0
2284 If Occurrences &gt; 0 And Occurrences = UBound(vSplit) - 1 Then Exit Do
2285 bSplit = False
2286 &apos; Ignore found Delimiter if in quoted string
2287 For i = lMin To lBound
2288 If lInStr &lt; vStart(i) Then
2289 bSplit = True
2290 Exit For
2291 ElseIf lInStr &gt; vStart(i) And lInStr &lt; vEnd (i) Then
2292 Exit For
2293 Else
2294 lMin = i + 1
2295 If i = lBound Then bSplit = True Else bSplit = ( lInStr &lt; vStart(lMin) )
2296 End If
2297 Next i
2298 &apos; Build next chunk and store in split array
2299 If bSplit Then
2300 If lInStrPrev = 0 Then &apos; First chunk
2301 sChunk = Left(InputStr, lInStr - 1)
2302 Else
2303 sChunk = Mid(InputStr, lInStrPrev + lDelimLen, lInStr - lInStrPrev - lDelimLen)
2304 End If
2305 vSplit = SF_Array.Append(vSplit, sChunk &amp; &quot;&quot;)
2306 lInStrPrev = lInStr
2307 End If
2308 lInStr = InStr(lInStr + lDelimLen, InputStr, Delimiter, 0)
2309 Loop
2310 If Occurrences = 0 Or Occurrences &gt; UBound(vSplit) + 1 Then
2311 sChunk = Mid(InputStr, lInStrPrev + lDelimLen) &apos; Append last chunk
2312 vSplit = SF_Array.Append(vSplit, sChunk &amp; &quot;&quot;)
2313 End If
2314 End If
2315 End If
2317 Finally:
2318 SplitNotQuoted = vSplit
2319 SF_Utils._ExitFunction(cstThisSub)
2320 Exit Function
2321 Catch:
2322 GoTo Finally
2323 End Function &apos; ScriptForge.SF_String.SplitNotQuoted
2325 REM -----------------------------------------------------------------------------
2326 Public Function StartsWith(Optional ByRef InputStr As Variant _
2327 , Optional ByVal Substring As Variant _
2328 , Optional ByVal CaseSensitive As Variant _
2329 ) As Boolean
2330 &apos;&apos;&apos; Returns True if the first characters of InputStr are identical to Substring
2331 &apos;&apos;&apos; Args:
2332 &apos;&apos;&apos; InputStr: the input string
2333 &apos;&apos;&apos; Substring: the prefixing characters
2334 &apos;&apos;&apos; CaseSensitive: default = False
2335 &apos;&apos;&apos; Returns:
2336 &apos;&apos;&apos; True if the comparison is satisfactory
2337 &apos;&apos;&apos; False if either InputStr or Substring have a length = 0
2338 &apos;&apos;&apos; False if Substr is longer than InputStr
2339 &apos;&apos;&apos; Examples:
2340 &apos;&apos;&apos; SF_String.StartsWith(&quot;abcdefg&quot;, &quot;ABC&quot;) returns True
2341 &apos;&apos;&apos; SF_String.StartsWith(&quot;abcdefg&quot;, &quot;ABC&quot;, CaseSensitive := True) returns False
2343 Dim bStartsWith As Boolean &apos; Return value
2344 Dim lSub As Long &apos; Length of SUbstring
2345 Const cstThisSub = &quot;String.StartsWith&quot;
2346 Const cstSubArgs = &quot;InputStr, Substring, [CaseSensitive=False]&quot;
2348 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2349 bStartsWith = False
2351 Check:
2352 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
2353 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2354 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2355 If Not SF_Utils._Validate(Substring, &quot;Substring&quot;, V_STRING) Then GoTo Finally
2356 If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
2357 End If
2359 Try:
2360 lSub = Len(Substring)
2361 If Len(InputStr) &gt; 0 And lSub &gt; 0 And lSub &lt;= Len(InputStr) Then
2362 bStartsWith = ( StrComp(Left(InputStr, lSub), Substring, Iif(CaseSensitive, 1, 0)) = 0 )
2363 End If
2365 Finally:
2366 StartsWith = bStartsWith
2367 SF_Utils._ExitFunction(cstThisSub)
2368 Exit Function
2369 Catch:
2370 GoTo Finally
2371 End Function &apos; ScriptForge.SF_String.StartsWith
2373 REM -----------------------------------------------------------------------------
2374 Public Function TrimExt(Optional ByRef InputStr As Variant) As String
2375 &apos;&apos;&apos; Return the input string without its leading and trailing whitespaces
2376 &apos;&apos;&apos; Args:
2377 &apos;&apos;&apos; InputStr: the input string
2378 &apos;&apos;&apos; Returns:
2379 &apos;&apos;&apos; The input string without its leading and trailing white spaces
2380 &apos;&apos;&apos; Examples:
2381 &apos;&apos;&apos; SF_String.TrimExt(&quot; ABCDE&quot; &amp; Chr(9) &amp; Chr(10) &amp; Chr(13) &amp; &quot; &quot;) returns &quot;ABCDE&quot;
2383 Dim sTrim As String &apos; Return value
2384 Const cstThisSub = &quot;String.TrimExt&quot;
2385 Const cstSubArgs = &quot;InputStr&quot;
2387 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2388 sTrim = &quot;&quot;
2390 Check:
2391 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2392 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2393 End If
2395 Try:
2396 If Len(InputStr) &gt; 0 Then
2397 sTrim = SF_String.ReplaceRegex(InputStr, REGEXLTRIM, &quot;&quot;) &apos; Trim left
2398 sTrim = SF_String.ReplaceRegex(sTrim, REGEXRTRIM, &quot;&quot;) &apos; Trim right
2399 End If
2401 Finally:
2402 TrimExt = sTrim
2403 SF_Utils._ExitFunction(cstThisSub)
2404 Exit Function
2405 Catch:
2406 GoTo Finally
2407 End Function &apos; ScriptForge.SF_String.TrimExt
2409 REM -----------------------------------------------------------------------------
2410 Public Function Unescape(Optional ByRef InputStr As Variant) As String
2411 &apos;&apos;&apos; Convert any escaped characters in the input string
2412 &apos;&apos;&apos; Args:
2413 &apos;&apos;&apos; InputStr: the input string
2414 &apos;&apos;&apos; Returns:
2415 &apos;&apos;&apos; The input string after replacement of \\, \n, \r, \t sequences
2416 &apos;&apos;&apos; Examples:
2417 &apos;&apos;&apos; SF_String.Unescape(&quot;abc\n\tdef\\n&quot;) returns &quot;abc&quot; &amp; Chr(10) &amp; Chr(9) &amp; &quot;def\n&quot;
2419 Dim sUnescape As String &apos; Return value
2420 Dim sToken As String &apos; Placeholder unlikely to be present in input string
2421 Const cstThisSub = &quot;String.Unescape&quot;
2422 Const cstSubArgs = &quot;InputStr&quot;
2424 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2425 sUnescape = &quot;&quot;
2427 Check:
2428 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2429 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2430 End If
2432 Try:
2433 sToken = Chr(1) &amp; &quot;$&quot; &amp; Chr(2) &amp; &quot;*&quot; &amp; Chr(3) &amp; &quot;$&quot; &amp; Chr(1) &apos; Placeholder for &quot;\\&quot;
2434 sUnescape = SF_String.ReplaceStr( InputStr _
2435 , Array(&quot;\\&quot;, &quot;\n&quot;, &quot;\r&quot;, &quot;\t&quot;, sToken) _
2436 , Array(sToken, SF_String.sfLF, SF_String.sfCR, SF_String.sfTAB, &quot;\&quot;) _
2439 Finally:
2440 Unescape = sUnescape
2441 SF_Utils._ExitFunction(cstThisSub)
2442 Exit Function
2443 Catch:
2444 GoTo Finally
2445 End Function &apos; ScriptForge.SF_String.Unescape
2447 REM -----------------------------------------------------------------------------
2448 Public Function Unquote(Optional ByRef InputStr As Variant _
2449 , Optional ByVal QuoteChar As String _
2450 ) As String
2451 &apos;&apos;&apos; Reset a quoted string to its original content
2452 &apos;&apos;&apos; (used f.i. for parsing of csv-like records)
2453 &apos;&apos;&apos; Args:
2454 &apos;&apos;&apos; InputStr: the input string
2455 &apos;&apos;&apos; QuoteChar: either &quot; (default) or &apos;
2456 &apos;&apos;&apos; Returns:
2457 &apos;&apos;&apos; The input string after removal of leading/trailing quotes and escaped single/double quotes
2458 &apos;&apos;&apos; The input string if not a quoted string
2459 &apos;&apos;&apos; Examples:
2460 &apos;&apos;&apos; SF_String.Unquote(&quot;&quot;&quot;àé&quot;&quot;&quot;&quot;n ΣlPµ Русский&quot;&quot;&quot;) returns &quot;àé&quot;&quot;n ΣlPµ Русский&quot;
2462 Dim sUnquote As String &apos; Return value
2463 Dim oCharacterClass As Object &apos; com.sun.star.i18n.CharacterClassification
2464 Dim oLocale As Object &apos; com.sun.star.lang.Locale
2465 Dim oParse As Object &apos; com.sun.star.i18n.ParseResult
2466 Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
2467 Const cstThisSub = &quot;String.Unquote&quot;
2468 Const cstSubArgs = &quot;InputStr&quot;
2470 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2471 sUnquote = &quot;&quot;
2473 Check:
2474 If IsMissing(QuoteChar) Or IsEmpty(QuoteChar) Then QuoteChar = cstDouble
2475 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2476 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2477 If Not SF_Utils._Validate(QuoteChar, &quot;QuoteChar&quot;, V_STRING, Array(cstDouble, cstSingle)) Then GoTo Finally
2478 End If
2480 Try:
2481 If Left(InputStr, 1) &lt;&gt; &quot;&quot;&quot;&quot; Then &apos; No need to parse further
2482 sUnquote = InputStr
2483 Else
2484 Set oCharacterClass = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
2485 Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
2487 &apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1i18n_1_1XCharacterClassification.html#ad5f1be91fbe86853200391f828d4166b
2488 Set oParse = oCharacterClass.parsePredefinedToken( _
2489 Iif(QuoteChar = cstDouble, com.sun.star.i18n.KParseType.DOUBLE_QUOTE_STRING, com.sun.star.i18n.KParseType.SINGLE_QUOTE_NAME) _
2490 , InputStr, 0, oLocale, 0, &quot;&quot;, 0, &quot;&quot;)
2491 If oParse.CharLen &gt; 0 Then &apos; Is parsing successful ?
2492 sUnquote = oParse.DequotedNameOrString
2493 Else
2494 sUnquote = InputStr
2495 End If
2496 End If
2498 Finally:
2499 Unquote = sUnquote
2500 SF_Utils._ExitFunction(cstThisSub)
2501 Exit Function
2502 Catch:
2503 GoTo Finally
2504 End Function &apos; ScriptForge.SF_String.Unquote
2506 REM -----------------------------------------------------------------------------
2507 Public Function Wrap(Optional ByRef InputStr As Variant _
2508 , Optional ByVal Width As Variant _
2509 , Optional ByVal TabSize As Variant _
2510 ) As Variant
2511 &apos;&apos;&apos; Wraps every single paragraph in text (a string) so every line is at most Width characters long
2512 &apos;&apos;&apos; Args:
2513 &apos;&apos;&apos; InputStr: the input string
2514 &apos;&apos;&apos; Width: the maximum number of characters in each line, default = 70
2515 &apos;&apos;&apos; TabSize: before wrapping the text, the existing TAB (Chr(9)) characters are replaced with spaces.
2516 &apos;&apos;&apos; TabSize defines the TAB positions at TabSize + 1, 2 * TabSize + 1 , ... N * TabSize + 1
2517 &apos;&apos;&apos; Default = 8
2518 &apos;&apos;&apos; Returns:
2519 &apos;&apos;&apos; Returns a zero-based array of output lines, without final newlines except the pre-existing line-breaks
2520 &apos;&apos;&apos; Tabs are expanded. Symbolic line breaks are replaced by their hard equivalents
2521 &apos;&apos;&apos; If the wrapped output has no content, the returned array is empty.
2522 &apos;&apos;&apos; Examples:
2523 &apos;&apos;&apos; SF_String.Wrap(&quot;Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...&quot;, 20)
2525 Dim vWrap As Variant &apos; Return value
2526 Dim vWrapLines &apos; Input string split on line breaks
2527 Dim sWrap As String &apos; Intermediate string
2528 Dim sLine As String &apos; Line after splitting on line breaks
2529 Dim lPos As Long &apos; Position in sLine already wrapped
2530 Dim lStart As Long &apos; Start position before and after regex search
2531 Dim sSpace As String &apos; Next whitespace
2532 Dim sChunk As String &apos; Next wrappable text chunk
2533 Const cstThisSub = &quot;String.Wrap&quot;
2534 Const cstSubArgs = &quot;InputStr, [Width=70], [TabSize=8]&quot;
2536 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2537 vWrap = Array()
2539 Check:
2540 If IsMissing(Width) Or IsEmpty(Width) Then Width = 70
2541 If IsMissing(TabSize) Or IsEmpty(TabSize) Then TabSize = 8
2542 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2543 If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2544 If Not SF_Utils._Validate(Width, &quot;Width&quot;, V_NUMERIC) Then GoTo Finally
2545 If Not SF_Utils._Validate(TabSize, &quot;TabSize&quot;, V_NUMERIC) Then GoTo Finally
2546 End If
2548 Try:
2549 If Len(InputStr) &gt; 0 Then
2550 sWrap = SF_String.Unescape(InputStr) &apos; Replace symbolic breaks
2551 sWrap = SF_String.ExpandTabs(sWrap, TabSize) &apos; Interpret TABs to have a meaningful Width
2552 &apos; First, split full string
2553 vWrapLines = SF_String.SplitLines(sWrap, KeepBreaks := True) &apos; Keep pre-existing breaks
2554 If UBound(vWrapLines) = 0 And Len(sWrap) &lt;= Width Then &apos; Output a single line
2555 vWrap = Array(sWrap)
2556 Else
2557 &apos; Second, split each line on Width
2558 For Each sLine In vWrapLines
2559 If Len(sLine) &lt;= Width Then
2560 If UBound(vWrap) &lt; 0 Then vWrap = Array(sLine) Else vWrap = SF_Array.Append(vWrap, sLine)
2561 Else
2562 &apos; Scan sLine and accumulate found substrings up to Width
2563 lStart = 1
2564 lPos = 0
2565 sWrap = &quot;&quot;
2566 Do While lStart &lt;= Len(sLine)
2567 sSpace = SF_String.FindRegex(sLine, REGEXSPACES, lStart)
2568 If lStart = 0 Then lStart = Len(sLine) + 1
2569 sChunk = Mid(sLine, lPos + 1, lStart - 1 - lPos + Len(sSpace))
2570 If Len(sWrap) + Len(sChunk) &lt; Width Then &apos; Add chunk to current piece of line
2571 sWrap = sWrap &amp; sChunk
2572 Else &apos; Save current line and initialize next one
2573 If UBound(vWrap) &lt; 0 Then vWrap = Array(sWrap) Else vWrap = SF_Array.Append(vWrap, sWrap)
2574 sWrap = sChunk
2575 End If
2576 lPos = lPos + Len(sChunk)
2577 lStart = lPos + 1
2578 Loop
2579 &apos; Add last chunk
2580 If Len(sWrap) &gt; 0 Then
2581 If UBound(vWrap) &lt; 0 Then vWrap = Array(sWrap) Else vWrap = SF_Array.Append(vWrap, sWrap)
2582 End If
2583 End If
2584 Next sLine
2585 End If
2586 End If
2588 Finally:
2589 Wrap = vWrap
2590 SF_Utils._ExitFunction(cstThisSub)
2591 Exit Function
2592 Catch:
2593 GoTo Finally
2594 End Function &apos; ScriptForge.SF_String.Wrap
2596 REM ============================================================= PRIVATE METHODS
2598 REM -----------------------------------------------------------------------------
2599 Private Function _Repr(ByRef pvString As String) As String
2600 &apos;&apos;&apos; Convert an arbitrary string to a readable string, typically for debugging purposes (DebugPrint ...)
2601 &apos;&apos;&apos; Carriage Returns are replaced by \r. Other line breaks are replaced by \n
2602 &apos;&apos;&apos; Tabs are replaced by \t
2603 &apos;&apos;&apos; Backslashes are doubled
2604 &apos;&apos;&apos; Other non printable characters are replaced by \x00 to \xFF or \x0000 to \xFFFF
2605 &apos;&apos;&apos; Args:
2606 &apos;&apos;&apos; pvString: the string to make readable
2607 &apos;&apos;&apos; Return:
2608 &apos;&apos;&apos; the converted string
2610 Dim sString As String &apos; Return value
2611 Dim sChar As String &apos; A single character
2612 Dim lAsc As Long &apos; Ascii value
2613 Dim lPos As Long &apos; Position in sString
2614 Dim i As Long
2616 &apos; Process TABs, CRs and LFs
2617 sString = Replace(Replace(Replace(pvString, &quot;\&quot;, &quot;\\&quot;), SF_String.sfCR, &quot;\r&quot;), SF_String.sfTAB, &quot;\t&quot;)
2618 sString = Join(SF_String.SplitLines(sString, KeepBreaks := False), &quot;\n&quot;)
2619 &apos; Process not printable characters
2620 If Len(sString) &gt; 0 Then
2621 lPos = 1
2622 Do While lPos &lt;= Len(sString)
2623 sChar = Mid(sString, lPos, 1)
2624 If Not SF_String.IsPrintable(sChar) Then
2625 lAsc = Asc(sChar)
2626 sChar = &quot;\x&quot; &amp; Iif(lAsc &lt; 255, Right(&quot;00&quot; &amp; Hex(lAsc, 2)), Right(&quot;0000&quot; &amp; Hex(lAsc, 4)))
2627 If lPos &lt; Len(sString) Then
2628 sString = Left(sString, lPos - 1) &amp; sChar &amp; Mid(sString, lPos + 1)
2629 Else
2630 sString = Left(sString, lPos - 1) &amp; sChar
2631 End If
2632 End If
2633 lPos = lPos + Len(sChar)
2634 Loop
2635 End If
2637 _Repr = sString
2639 End Function &apos; ScriptForge.SF_String._Repr
2641 REM ================================================ END OF SCRIPTFORGE.SF_STRING
2642 </script:module>