SF_String.xba 114 KB

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