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