SF_String.xba 114 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643
  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>