strutils.pp 98 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731
  1. {
  2. Delphi/Kylix compatibility unit: String handling routines.
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2005 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. {$inline on}
  14. unit StrUtils;
  15. interface
  16. uses
  17. SysUtils, Types;
  18. { ---------------------------------------------------------------------
  19. Case insensitive search/replace
  20. ---------------------------------------------------------------------}
  21. Function AnsiResemblesText(const AText, AOther: AnsiString): Boolean;
  22. Function AnsiContainsText(const AText, ASubText: AnsiString): Boolean;
  23. Function AnsiStartsText(const ASubText, AText: AnsiString): Boolean;
  24. Function AnsiEndsText(const ASubText, AText: AnsiString): Boolean;
  25. function AnsiEndsText(const ASubText, AText: UnicodeString): Boolean;
  26. Function AnsiReplaceText(const AText, AFromText, AToText: AnsiString): AnsiString;inline;
  27. Function AnsiMatchText(const AText: AnsiString; const AValues: array of AnsiString): Boolean;inline;
  28. Function AnsiIndexText(const AText: AnsiString; const AValues: array of AnsiString): Integer;
  29. Function StartsText(const ASubText, AText: string): Boolean; inline;
  30. Function EndsText(const ASubText, AText: string): Boolean; inline;
  31. function ResemblesText(const AText, AOther: string): Boolean; inline;
  32. function ContainsText(const AText, ASubText: string): Boolean; inline;
  33. function MatchText(const AText: Ansistring; const AValues: array of Ansistring): Boolean; inline;
  34. function IndexText(const AText: Ansistring; const AValues: array of Ansistring): Integer; inline;
  35. { ---------------------------------------------------------------------
  36. Case sensitive search/replace
  37. ---------------------------------------------------------------------}
  38. Function AnsiContainsStr(const AText, ASubText: AnsiString): Boolean;inline;
  39. function AnsiContainsStr(const AText, ASubText: Unicodestring): Boolean; inline;
  40. Function AnsiStartsStr(const ASubText, AText: AnsiString): Boolean;
  41. Function AnsiStartsStr(const ASubText, AText: UnicodeString): Boolean;
  42. Function AnsiEndsStr(const ASubText, AText: AnsiString): Boolean;
  43. Function AnsiEndsStr(const ASubText, AText: UnicodeString): Boolean;
  44. Function AnsiReplaceStr(const AText, AFromText, AToText: AnsiString): AnsiString;inline;
  45. Function AnsiMatchStr(const AText: AnsiString; const AValues: array of AnsiString): Boolean;inline;
  46. Function AnsiIndexStr(const AText: Ansistring; const AValues: array of Ansistring): Integer;
  47. Function StartsStr(const ASubText, AText: string): Boolean;
  48. Function EndsStr(const ASubText, AText: string): Boolean;
  49. Function MatchStr(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  50. Function MatchText(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  51. Function IndexStr(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  52. Function IndexText(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  53. Operator in (const AText: Ansistring; const AValues: array of Ansistring):Boolean;inline;
  54. Operator in (const AText: UnicodeString; const AValues: array of UnicodeString):Boolean;inline;
  55. function ContainsStr(const AText, ASubText: string): Boolean; inline;
  56. function MatchStr(const AText: Ansistring; const AValues: array of Ansistring): Boolean; inline;
  57. function IndexStr(const AText: Ansistring; const AValues: array of Ansistring): Integer; inline;
  58. { ---------------------------------------------------------------------
  59. Miscellaneous
  60. ---------------------------------------------------------------------}
  61. Function DupeString(const AText: string; ACount: Integer): string;
  62. Function ReverseString(const AText: string): string;
  63. Function AnsiReverseString(const AText: AnsiString): AnsiString;inline;
  64. Function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
  65. Function RandomFrom(const AValues: array of string): string; overload;
  66. Function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string = ''): string; overload;
  67. Function IfThen(AValue: Boolean; const ATrue: TStringDynArray; const AFalse: TStringDynArray = nil): TStringDynArray; overload;
  68. function NaturalCompareText (const S1 , S2 : string ): Integer ;
  69. function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: AnsiChar): Integer;
  70. function SplitString(const S, Delimiters: string): TRTLStringDynArray;
  71. { ---------------------------------------------------------------------
  72. VB emulations.
  73. ---------------------------------------------------------------------}
  74. Function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
  75. Function RightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  76. Function MidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;inline;
  77. Function RightBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;inline;
  78. Function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: SizeInt): AnsiString;inline;
  79. Function AnsiLeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
  80. Function AnsiRightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
  81. Function AnsiMidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;inline;
  82. Function LeftBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;inline;
  83. Function LeftStr(const AText: WideString; const ACount: SizeInt): WideString;inline;
  84. Function RightStr(const AText: WideString; const ACount: SizeInt): WideString;
  85. Function MidStr(const AText: WideString; const AStart, ACount: SizeInt): WideString;inline;
  86. { ---------------------------------------------------------------------
  87. Extended search and replace
  88. ---------------------------------------------------------------------}
  89. const
  90. { Default word delimiters are any character except the core alphanumerics. }
  91. WordDelimiters: set of AnsiChar = [#0..#255] - ['a'..'z','A'..'Z','1'..'9','0'];
  92. resourcestring
  93. SErrAmountStrings = 'Amount of search and replace strings don''t match';
  94. type
  95. TStringSearchOption = (soDown, soMatchCase, soWholeWord);
  96. TStringSearchOptions = set of TStringSearchOption;
  97. TStringSeachOption = TStringSearchOption;
  98. Function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String; Options: TStringSearchOptions): PAnsiChar;
  99. Function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String): PAnsiChar;inline; // ; Options: TStringSearchOptions = [soDown]
  100. Function PosEx(const SubStr, S: Ansistring; Offset: SizeUint): SizeInt;
  101. Function PosEx(const SubStr, S: Ansistring): SizeInt;inline; // Offset: Cardinal = 1
  102. Function PosEx(c:AnsiChar; const S: AnsiString; Offset: SizeUint): SizeInt;
  103. Function PosEx(const SubStr, S: UnicodeString; Offset: SizeUint): SizeInt;
  104. Function PosEx(c: WideChar; const S: UnicodeString; Offset: SizeUint): SizeInt;
  105. Function PosEx(const SubStr, S: UnicodeString): Sizeint;inline; // Offset: Cardinal = 1
  106. function StringsReplace(const S: Ansistring; OldPattern, NewPattern: array of Ansistring; Flags: TReplaceFlags): string;
  107. { ---------------------------------------------------------------------
  108. Delphi compat
  109. ---------------------------------------------------------------------}
  110. Function ReplaceStr(const AText, AFromText, AToText: string): string;inline;
  111. Function ReplaceText(const AText, AFromText, AToText: string): string;inline;
  112. { ---------------------------------------------------------------------
  113. Soundex Functions.
  114. ---------------------------------------------------------------------}
  115. type
  116. TSoundexLength = 1..MaxInt;
  117. Function Soundex(const AText: string; ALength: TSoundexLength): string;
  118. Function Soundex(const AText: string): string;inline; // ; ALength: TSoundexLength = 4
  119. type
  120. TSoundexIntLength = 1..8;
  121. Function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
  122. Function SoundexInt(const AText: string): Integer;inline; //; ALength: TSoundexIntLength = 4
  123. Function DecodeSoundexInt(AValue: Integer): string;
  124. Function SoundexWord(const AText: string): Word;
  125. Function DecodeSoundexWord(AValue: Word): string;
  126. Function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;inline;
  127. Function SoundexSimilar(const AText, AOther: string): Boolean;inline; //; ALength: TSoundexLength = 4
  128. Function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;inline;
  129. Function SoundexCompare(const AText, AOther: string): Integer;inline; //; ALength: TSoundexLength = 4
  130. Function SoundexProc(const AText, AOther: string): Boolean;
  131. type
  132. TCompareTextProc = Function(const AText, AOther: string): Boolean;
  133. Const
  134. AnsiResemblesProc: TCompareTextProc = @SoundexProc;
  135. ResemblesProc: TCompareTextProc = @SoundexProc;
  136. { ---------------------------------------------------------------------
  137. Other functions, based on RxStrUtils.
  138. ---------------------------------------------------------------------}
  139. type
  140. TRomanConversionStrictness = (rcsStrict, rcsRelaxed, rcsDontCare);
  141. resourcestring
  142. SInvalidRomanNumeral = '%s is not a valid Roman numeral';
  143. function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
  144. function DelSpace(const S: string): string;
  145. function DelChars(const S: string; Chr: AnsiChar): string;
  146. function DelChars(const S: string; Chars: TSysCharSet): string;
  147. function DelSpace1(const S: string): string;
  148. function Tab2Space(const S: string; Numb: Byte): string;
  149. function NPos(const C: string; S: string; N: Integer): SizeInt;
  150. Function RPosEx(C:AnsiChar;const S : AnsiString;offs:cardinal):SizeInt; overload;
  151. Function RPosEx(C:Unicodechar;const S : UnicodeString;offs:cardinal):SizeInt; overload;
  152. Function RPosEx(Const Substr : AnsiString; Const Source : AnsiString;offs:cardinal) : SizeInt; overload;
  153. Function RPosEx(Const Substr : UnicodeString; Const Source : UnicodeString;offs:cardinal) : SizeInt; overload;
  154. Function RPos(c:AnsiChar;const S : AnsiString):SizeInt; overload;
  155. Function RPos(c:Unicodechar;const S : UnicodeString):SizeInt; overload;
  156. Function RPos(Const Substr : AnsiString; Const Source : AnsiString) : SizeInt; overload;
  157. Function RPos(Const Substr : UnicodeString; Const Source : UnicodeString) : SizeInt; overload;
  158. function AddChar(C: AnsiChar; const S: string; N: Integer): string;
  159. function AddCharR(C: AnsiChar; const S: string; N: Integer): string;
  160. function PadLeft(const S: string; N: Integer): string;inline;
  161. function PadRight(const S: string; N: Integer): string;inline;
  162. function PadCenter(const S: string; Len: SizeInt): string;
  163. function Copy2Symb(const S: string; Symb: AnsiChar): string;
  164. function Copy2SymbDel(var S: string; Symb: AnsiChar): string;
  165. function Copy2Space(const S: string): string;inline;
  166. function Copy2SpaceDel(var S: string): string;inline;
  167. function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
  168. function WordCount(const S: string; const WordDelims: TSysCharSet): SizeInt;
  169. function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): SizeInt;
  170. function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
  171. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  172. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: SizeInt): string;
  173. {$ENDIF}
  174. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: Integer): string;
  175. function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
  176. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  177. function ExtractSubstr(const S: string; var Pos: SizeInt; const Delims: TSysCharSet): string;
  178. {$ENDIF}
  179. function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
  180. function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
  181. function FindPart(const HelpWilds, InputStr: string): SizeInt;
  182. function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
  183. function XorString(const Key, Src: ShortString): ShortString;
  184. function XorEncode(const Key, Source: Ansistring): Ansistring;
  185. function XorDecode(const Key, Source: Ansistring): Ansistring;
  186. function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
  187. function Numb2USA(const S: string): string;
  188. function Hex2Dec(const S: string): Longint;
  189. function Hex2Dec64(const S: string): int64;
  190. function Dec2Numb(N: Longint; Len, Base: Byte): string;
  191. function Numb2Dec(S: string; Base: Byte): Longint;
  192. function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
  193. function IntToBin(Value: Longint; Digits: Integer): string;
  194. function IntToBin(Value: int64; Digits:integer): string;
  195. function IntToRoman(Value: Longint): string;
  196. function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
  197. function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  198. function RomanToIntDef(Const S : String; const ADefault: Longint = 0; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  199. procedure BinToHex(const BinBuffer: TBytes; BinBufOffset: Integer; var HexBuffer: TBytes; HexBufOffset: Integer; Count: Integer); overload;
  200. procedure BinToHex(BinValue: Pointer; HexValue: PWideChar; BinBufSize: Integer); overload;
  201. procedure BinToHex(const BinValue; HexValue: PWideChar; BinBufSize: Integer); overload;
  202. procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer); overload;
  203. procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer); overload;
  204. procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer); overload;
  205. procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer); overload;
  206. function HexToBin(HexValue, BinValue: PAnsiChar; BinBufSize: Integer): Integer;
  207. const
  208. DigitChars = ['0'..'9'];
  209. Brackets = ['(',')','[',']','{','}'];
  210. StdWordDelims = [#0..' ',',','.',';','/','\',':','''','"','`'] + Brackets;
  211. StdSwitchChars = ['-','/'];
  212. function PosSet (const c:TSysCharSet;const s : ansistring ):SizeInt;
  213. function PosSet (const c:string;const s : ansistring ):SizeInt;
  214. function PosSetEx (const c:TSysCharSet;const s : ansistring;count:Integer ):SizeInt;
  215. function PosSetEx (const c:string;const s : ansistring;count:Integer ):SizeInt;
  216. Procedure RemoveLeadingChars(VAR S : AnsiString; Const CSet:TSysCharset);
  217. Procedure RemoveTrailingChars(VAR S : AnsiString;Const CSet:TSysCharset);
  218. Procedure RemoveLeadingChars(VAR S : UnicodeString; Const CSet:TSysCharset);
  219. Procedure RemoveTrailingChars(VAR S : UnicodeString;Const CSet:TSysCharset);
  220. Procedure RemovePadChars(VAR S : AnsiString;Const CSet:TSysCharset);
  221. function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
  222. Function TrimRightSet(const S: String;const CSet:TSysCharSet): String;
  223. function TrimSet(const S: String;const CSet:TSysCharSet): String;
  224. type
  225. SizeIntArray = array of SizeInt;
  226. Function FindMatchesBoyerMooreCaseSensitive(const S,OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  227. Function FindMatchesBoyerMooreCaseSensitive(const S,OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  228. Function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  229. Function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  230. Type
  231. TStringReplaceAlgorithm = (sraDefault, // Default algoritm as used in StringUtils.
  232. sraManySmall, // Algorithm optimized for many small replacements.
  233. sraBoyerMoore // Algorithm optimized for long replacements.
  234. );
  235. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
  236. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
  237. { We need these for backwards compatibility:
  238. The compiler will stop searching and convert to ansistring if the widestring version of stringreplace is used.
  239. They currently simply refer to sysutils, till the new mechanisms are proven to work with unicode.}
  240. {$IF SIZEOF(CHAR)=1}
  241. Function StringReplace(const S, OldPattern, NewPattern: unicodestring; Flags: TReplaceFlags): unicodestring; overload;
  242. Function StringReplace(const S, OldPattern, NewPattern: widestring; Flags: TReplaceFlags): widestring; overload;
  243. {$ENDIF}
  244. Type
  245. TRawByteStringArray = Array of RawByteString;
  246. TUnicodeStringArray = Array of UnicodeString;
  247. Function SplitCommandLine(S : RawByteString) : TRawByteStringArray;
  248. Function SplitCommandLine(S : UnicodeString) : TUnicodeStringArray;
  249. implementation
  250. uses sysconst; // HexDigits
  251. (*
  252. FindMatchesBoyerMooreCaseSensitive
  253. Finds one or many ocurrences of an ansistring in another ansistring.
  254. It is case sensitive.
  255. * Parameters:
  256. S: The PAnsiChar to be searched in. (Read only).
  257. OldPattern: The PAnsiChar to be searched. (Read only).
  258. SSize: The size of S in Chars. (Read only).
  259. OldPatternSize: The size of OldPatter in chars. (Read only).
  260. aMatches: SizeInt array where match indexes are returned (zero based) (write only).
  261. aMatchAll: Finds all matches, not just the first one. (Read only).
  262. * Returns:
  263. Nothing, information returned in aMatches parameter.
  264. The function is based in the Boyer-Moore algorithm.
  265. *)
  266. function FindMatchesBoyerMooreCaseSensitive(const S, OldPattern: PAnsiChar;
  267. const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray;
  268. const aMatchAll: Boolean) : Boolean;
  269. const
  270. ALPHABET_LENGHT=256;
  271. MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
  272. var
  273. //Stores the amount of replaces that will take place
  274. MatchesCount: SizeInt;
  275. //Currently allocated space for matches.
  276. MatchesAllocatedLimit: SizeInt;
  277. type
  278. AlphabetArray=array [0..ALPHABET_LENGHT-1] of SizeInt;
  279. function Max(const a1,a2: SizeInt): SizeInt;
  280. begin
  281. if a1>a2 then Result:=a1 else Result:=a2;
  282. end;
  283. procedure MakeDeltaJumpTable1(out DeltaJumpTable1: AlphabetArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  284. var
  285. i: SizeInt;
  286. begin
  287. for i := 0 to ALPHABET_LENGHT-1 do begin
  288. DeltaJumpTable1[i]:=aPatternSize;
  289. end;
  290. //Last AnsiChar do not enter in the equation
  291. for i := 0 to aPatternSize - 1 - 1 do begin
  292. DeltaJumpTable1[Ord(aPattern[i])]:=aPatternSize -1 - i;
  293. end;
  294. end;
  295. function IsPrefix(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): Boolean;
  296. var
  297. i: SizeInt;
  298. SuffixLength: SizeInt;
  299. begin
  300. SuffixLength:=aPatternSize-aPos;
  301. for i := 0 to SuffixLength-1 do begin
  302. if (aPattern[i] <> aPattern[aPos+i]) then begin
  303. exit(false);
  304. end;
  305. end;
  306. Result:=true;
  307. end;
  308. function SuffixLength(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): SizeInt;
  309. var
  310. i: SizeInt;
  311. begin
  312. i:=0;
  313. while (i<aPos) and (aPattern[aPos-i] = aPattern[aPatternSize-1-i]) do begin
  314. inc(i);
  315. end;
  316. Result:=i;
  317. end;
  318. procedure MakeDeltaJumpTable2(var DeltaJumpTable2: SizeIntArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  319. var
  320. Position: SizeInt;
  321. LastPrefixIndex: SizeInt;
  322. SuffixLengthValue: SizeInt;
  323. begin
  324. LastPrefixIndex:=aPatternSize-1;
  325. Position:=aPatternSize-1;
  326. while Position>=0 do begin
  327. if IsPrefix(aPattern,aPatternSize,Position+1) then begin
  328. LastPrefixIndex := Position+1;
  329. end;
  330. DeltaJumpTable2[Position] := LastPrefixIndex + (aPatternSize-1 - Position);
  331. Dec(Position);
  332. end;
  333. Position:=0;
  334. while Position<aPatternSize-1 do begin
  335. SuffixLengthValue:=SuffixLength(aPattern,aPatternSize,Position);
  336. if aPattern[Position-SuffixLengthValue] <> aPattern[aPatternSize-1 - SuffixLengthValue] then begin
  337. DeltaJumpTable2[aPatternSize - 1 - SuffixLengthValue] := aPatternSize - 1 - Position + SuffixLengthValue;
  338. end;
  339. Inc(Position);
  340. end;
  341. end;
  342. //Resizes the allocated space for replacement index
  343. procedure ResizeAllocatedMatches;
  344. begin
  345. MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
  346. SetLength(aMatches,MatchesAllocatedLimit);
  347. end;
  348. //Add a match to be replaced
  349. procedure AddMatch(const aPosition: SizeInt); inline;
  350. begin
  351. if MatchesCount = MatchesAllocatedLimit then begin
  352. ResizeAllocatedMatches;
  353. end;
  354. aMatches[MatchesCount]:=aPosition;
  355. inc(MatchesCount);
  356. end;
  357. var
  358. i,j: SizeInt;
  359. DeltaJumpTable1: array [0..ALPHABET_LENGHT-1] of SizeInt;
  360. DeltaJumpTable2: SizeIntArray;
  361. begin
  362. MatchesCount:=0;
  363. MatchesAllocatedLimit:=0;
  364. SetLength(aMatches,MatchesCount);
  365. if OldPatternSize=0 then begin
  366. Exit;
  367. end;
  368. SetLength(DeltaJumpTable2,OldPatternSize);
  369. MakeDeltaJumpTable1(DeltaJumpTable1,OldPattern,OldPatternSize);
  370. MakeDeltaJumpTable2(DeltaJumpTable2,OldPattern,OldPatternSize);
  371. i:=OldPatternSize-1;
  372. while i < SSize do begin
  373. j:=OldPatternSize-1;
  374. while (j>=0) and (S[i] = OldPattern[j]) do begin
  375. dec(i);
  376. dec(j);
  377. end;
  378. if (j<0) then begin
  379. AddMatch(i+1);
  380. //Only first match ?
  381. if not aMatchAll then break;
  382. inc(i,DeltaJumpTable2[0]+1);
  383. end else begin
  384. i:=i + Max(DeltaJumpTable1[ord(s[i])],DeltaJumpTable2[j]);
  385. end;
  386. end;
  387. SetLength(aMatches,MatchesCount);
  388. Result:=MatchesCount>0;
  389. end;
  390. function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out
  391. aMatches: SizeIntArray; const aMatchAll: Boolean): Boolean;
  392. const
  393. ALPHABET_LENGHT=256;
  394. MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
  395. var
  396. //Lowercased OldPattern
  397. lPattern: string;
  398. //Array of lowercased alphabet
  399. lCaseArray: array [0..ALPHABET_LENGHT-1] of AnsiChar;
  400. //Stores the amount of replaces that will take place
  401. MatchesCount: SizeInt;
  402. //Currently allocated space for matches.
  403. MatchesAllocatedLimit: SizeInt;
  404. type
  405. AlphabetArray=array [0..ALPHABET_LENGHT-1] of SizeInt;
  406. function Max(const a1,a2: SizeInt): SizeInt;
  407. begin
  408. if a1>a2 then Result:=a1 else Result:=a2;
  409. end;
  410. procedure MakeDeltaJumpTable1(out DeltaJumpTable1: AlphabetArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  411. var
  412. i: SizeInt;
  413. begin
  414. for i := 0 to ALPHABET_LENGHT-1 do begin
  415. DeltaJumpTable1[i]:=aPatternSize;
  416. end;
  417. //Last AnsiChar do not enter in the equation
  418. for i := 0 to aPatternSize - 1 - 1 do begin
  419. DeltaJumpTable1[Ord(aPattern[i])]:=aPatternSize - 1 - i;
  420. end;
  421. end;
  422. function IsPrefix(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): Boolean; inline;
  423. var
  424. i: SizeInt;
  425. SuffixLength: SizeInt;
  426. begin
  427. SuffixLength:=aPatternSize-aPos;
  428. for i := 0 to SuffixLength-1 do begin
  429. if (aPattern[i+1] <> aPattern[aPos+i]) then begin
  430. exit(false);
  431. end;
  432. end;
  433. Result:=true;
  434. end;
  435. function SuffixLength(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): SizeInt; inline;
  436. var
  437. i: SizeInt;
  438. begin
  439. i:=0;
  440. while (i<aPos) and (aPattern[aPos-i] = aPattern[aPatternSize-1-i]) do begin
  441. inc(i);
  442. end;
  443. Result:=i;
  444. end;
  445. procedure MakeDeltaJumpTable2(var DeltaJumpTable2: SizeIntArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  446. var
  447. Position: SizeInt;
  448. LastPrefixIndex: SizeInt;
  449. SuffixLengthValue: SizeInt;
  450. begin
  451. LastPrefixIndex:=aPatternSize-1;
  452. Position:=aPatternSize-1;
  453. while Position>=0 do begin
  454. if IsPrefix(aPattern,aPatternSize,Position+1) then begin
  455. LastPrefixIndex := Position+1;
  456. end;
  457. DeltaJumpTable2[Position] := LastPrefixIndex + (aPatternSize-1 - Position);
  458. Dec(Position);
  459. end;
  460. Position:=0;
  461. while Position<aPatternSize-1 do begin
  462. SuffixLengthValue:=SuffixLength(aPattern,aPatternSize,Position);
  463. if aPattern[Position-SuffixLengthValue] <> aPattern[aPatternSize-1 - SuffixLengthValue] then begin
  464. DeltaJumpTable2[aPatternSize - 1 - SuffixLengthValue] := aPatternSize - 1 - Position + SuffixLengthValue;
  465. end;
  466. Inc(Position);
  467. end;
  468. end;
  469. //Resizes the allocated space for replacement index
  470. procedure ResizeAllocatedMatches;
  471. begin
  472. MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
  473. SetLength(aMatches,MatchesAllocatedLimit);
  474. end;
  475. //Add a match to be replaced
  476. procedure AddMatch(const aPosition: SizeInt); inline;
  477. begin
  478. if MatchesCount = MatchesAllocatedLimit then begin
  479. ResizeAllocatedMatches;
  480. end;
  481. aMatches[MatchesCount]:=aPosition;
  482. inc(MatchesCount);
  483. end;
  484. var
  485. i,j: SizeInt;
  486. DeltaJumpTable1: array [0..ALPHABET_LENGHT-1] of SizeInt;
  487. DeltaJumpTable2: SizeIntArray;
  488. //Pointer to lowered OldPattern
  489. plPattern: PAnsiChar;
  490. begin
  491. MatchesCount:=0;
  492. MatchesAllocatedLimit:=0;
  493. SetLength(aMatches,MatchesCount);
  494. if OldPatternSize=0 then begin
  495. Exit;
  496. end;
  497. //Build an internal array of lowercase version of every possible AnsiChar.
  498. for j := 0 to Pred(ALPHABET_LENGHT) do begin
  499. lCaseArray[j]:=AnsiLowerCase(AnsiChar(j))[1];
  500. end;
  501. //Create the new lowercased pattern
  502. SetLength(lPattern,OldPatternSize);
  503. for j := 0 to Pred(OldPatternSize) do begin
  504. lPattern[j+1]:=lCaseArray[ord(OldPattern[j])];
  505. end;
  506. SetLength(DeltaJumpTable2,OldPatternSize);
  507. MakeDeltaJumpTable1(DeltaJumpTable1,@lPattern[1],OldPatternSize);
  508. MakeDeltaJumpTable2(DeltaJumpTable2,@lPattern[1],OldPatternSize);
  509. plPattern:=@lPattern[1];
  510. i:=OldPatternSize-1;
  511. while i < SSize do begin
  512. j:=OldPatternSize-1;
  513. while (j>=0) and (lCaseArray[Ord(S[i])] = plPattern[j]) do begin
  514. dec(i);
  515. dec(j);
  516. end;
  517. if (j<0) then begin
  518. AddMatch(i+1);
  519. //Only first match ?
  520. if not aMatchAll then break;
  521. inc(i,DeltaJumpTable2[0]+1);
  522. end else begin
  523. i:=i + Max(DeltaJumpTable1[Ord(lCaseArray[Ord(s[i])])],DeltaJumpTable2[j]);
  524. end;
  525. end;
  526. SetLength(aMatches,MatchesCount);
  527. Result:=MatchesCount>0;
  528. end;
  529. function StringReplaceFast(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer): string;
  530. const
  531. MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
  532. var
  533. //Stores where a replace will take place
  534. Matches: array of SizeInt;
  535. //Stores the amount of replaces that will take place
  536. MatchesCount: SizeInt;
  537. //Currently allocated space for matches.
  538. MatchesAllocatedLimit: SizeInt;
  539. //Uppercase version of pattern
  540. PatternUppercase: string;
  541. //Lowercase version of pattern
  542. PatternLowerCase: string;
  543. //Index
  544. MatchIndex: SizeInt;
  545. MatchLimit: SizeInt;
  546. MatchInternal: SizeInt;
  547. MatchTarget: SizeInt;
  548. AdvanceIndex: SizeInt;
  549. //Miscelanous variables
  550. OldPatternSize: SizeInt;
  551. NewPatternSize: SizeInt;
  552. //Resizes the allocated space for replacement index
  553. procedure ResizeAllocatedMatches;
  554. begin
  555. MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
  556. SetLength(Matches,MatchesAllocatedLimit);
  557. end;
  558. //Add a match to be replaced
  559. procedure AddMatch(const aPosition: SizeInt); inline;
  560. begin
  561. if MatchesCount = MatchesAllocatedLimit then begin
  562. ResizeAllocatedMatches;
  563. end;
  564. Matches[MatchesCount]:=aPosition;
  565. inc(MatchesCount);
  566. end;
  567. begin
  568. aCount:=0;
  569. if (OldPattern='') or (Length(OldPattern)>Length(S)) then begin
  570. //This cases will never match nothing.
  571. Result:=S;
  572. exit;
  573. end;
  574. Result:='';
  575. OldPatternSize:=Length(OldPattern);
  576. MatchesCount:=0;
  577. MatchesAllocatedLimit:=0;
  578. if rfIgnoreCase in Flags then begin
  579. //Different algorithm for case sensitive and insensitive
  580. //This is insensitive, so 2 new ansistrings are created for search pattern, one upper and one lower case.
  581. //It is easy, usually, to create 2 versions of the match pattern than uppercased and lowered case each
  582. //character in the "to be matched" string.
  583. PatternUppercase:=AnsiUpperCase(OldPattern);
  584. PatternLowerCase:=AnsiLowerCase(OldPattern);
  585. MatchIndex:=Length(OldPattern);
  586. MatchLimit:=Length(S);
  587. NewPatternSize:=Length(NewPattern);
  588. while MatchIndex <= MatchLimit do begin
  589. if (S[MatchIndex]=PatternLowerCase[OldPatternSize]) or (S[MatchIndex]=PatternUppercase[OldPatternSize]) then begin
  590. //Match backwards...
  591. MatchInternal:=OldPatternSize-1;
  592. MatchTarget:=MatchIndex-1;
  593. while MatchInternal>=1 do begin
  594. if (S[MatchTarget]=PatternLowerCase[MatchInternal]) or (S[MatchTarget]=PatternUppercase[MatchInternal]) then begin
  595. dec(MatchInternal);
  596. dec(MatchTarget);
  597. end else begin
  598. break;
  599. end;
  600. end;
  601. if MatchInternal=0 then begin
  602. //Match found, all AnsiChar meet the sequence
  603. //MatchTarget points to AnsiChar before, so matching is +1
  604. AddMatch(MatchTarget+1);
  605. inc(MatchIndex,OldPatternSize);
  606. if not (rfReplaceAll in Flags) then begin
  607. break;
  608. end;
  609. end else begin
  610. //Match not found
  611. inc(MatchIndex);
  612. end;
  613. end else begin
  614. inc(MatchIndex);
  615. end;
  616. end;
  617. end else begin
  618. //Different algorithm for case sensitive and insensitive
  619. //This is sensitive, so just 1 binary comprare
  620. MatchIndex:=Length(OldPattern);
  621. MatchLimit:=Length(S);
  622. NewPatternSize:=Length(NewPattern);
  623. while MatchIndex <= MatchLimit do begin
  624. if (S[MatchIndex]=OldPattern[OldPatternSize]) then begin
  625. //Match backwards...
  626. MatchInternal:=OldPatternSize-1;
  627. MatchTarget:=MatchIndex-1;
  628. while MatchInternal>=1 do begin
  629. if (S[MatchTarget]=OldPattern[MatchInternal]) then begin
  630. dec(MatchInternal);
  631. dec(MatchTarget);
  632. end else begin
  633. break;
  634. end;
  635. end;
  636. if MatchInternal=0 then begin
  637. //Match found, all AnsiChar meet the sequence
  638. //MatchTarget points to AnsiChar before, so matching is +1
  639. AddMatch(MatchTarget+1);
  640. inc(MatchIndex,OldPatternSize);
  641. if not (rfReplaceAll in Flags) then begin
  642. break;
  643. end;
  644. end else begin
  645. //Match not found
  646. inc(MatchIndex);
  647. end;
  648. end else begin
  649. inc(MatchIndex);
  650. end;
  651. end;
  652. end;
  653. //Create room enough for the result string
  654. aCount:=MatchesCount;
  655. SetLength(Result,Length(S)-OldPatternSize*MatchesCount+NewPatternSize*MatchesCount);
  656. MatchIndex:=1;
  657. MatchTarget:=1;
  658. //Matches[x] are 1 based offsets
  659. for MatchInternal := 0 to Pred(MatchesCount) do begin
  660. //Copy information up to next match
  661. AdvanceIndex:=Matches[MatchInternal]-MatchIndex;
  662. if AdvanceIndex>0 then begin
  663. move(S[MatchIndex],Result[MatchTarget],AdvanceIndex);
  664. inc(MatchTarget,AdvanceIndex);
  665. inc(MatchIndex,AdvanceIndex);
  666. end;
  667. //Copy the new replace information string
  668. if NewPatternSize>0 then begin
  669. move(NewPattern[1],Result[MatchTarget],NewPatternSize);
  670. inc(MatchTarget,NewPatternSize);
  671. end;
  672. inc(MatchIndex,OldPatternSize);
  673. end;
  674. if MatchTarget<=Length(Result) then begin
  675. //Add remain data at the end of source.
  676. move(S[MatchIndex],Result[MatchTarget],Length(Result)-MatchTarget+1);
  677. end;
  678. end;
  679. (*
  680. StringReplaceBoyerMoore
  681. Replaces one or many ocurrences of an ansistring in another ansistring by a new one.
  682. It can perform the compare ignoring case (ansi).
  683. * Parameters (Read only):
  684. S: The string to be searched in.
  685. OldPattern: The string to be searched.
  686. NewPattern: The string to replace OldPattern matches.
  687. Flags:
  688. rfReplaceAll: Replace all occurrences.
  689. rfIgnoreCase: Ignore case in OldPattern matching.
  690. * Returns:
  691. The modified string (if needed).
  692. It is memory conservative, just sizeof(SizeInt) per match in blocks off 100 matches
  693. plus Length(OldPattern)*2 in the case of ignoring case.
  694. Memory copies are the minimun necessary.
  695. Algorithm based in the Boyer-Moore string search algorithm.
  696. It is faster when the "S" string is very long and the OldPattern is also
  697. very big. As much big the OldPattern is, faster the search is too.
  698. It uses 2 different helper versions of Boyer-Moore algorithm, one for case
  699. sensitive and one for case INsensitive for speed reasons.
  700. *)
  701. function StringReplaceBoyerMoore(const S, OldPattern, NewPattern: string;Flags: TReplaceFlags; out aCount : Integer): string;
  702. var
  703. Matches: SizeIntArray;
  704. OldPatternSize: SizeInt;
  705. NewPatternSize: SizeInt;
  706. MatchesCount: SizeInt;
  707. MatchIndex: SizeInt;
  708. MatchTarget: SizeInt;
  709. MatchInternal: SizeInt;
  710. AdvanceIndex: SizeInt;
  711. begin
  712. aCount:=0;
  713. OldPatternSize:=Length(OldPattern);
  714. NewPatternSize:=Length(NewPattern);
  715. if (OldPattern='') or (Length(OldPattern)>Length(S)) then begin
  716. Result:=S;
  717. exit;
  718. end;
  719. if rfIgnoreCase in Flags then begin
  720. FindMatchesBoyerMooreCaseINSensitive(@s[1],@OldPattern[1],Length(S),Length(OldPattern),Matches, rfReplaceAll in Flags);
  721. end else begin
  722. FindMatchesBoyerMooreCaseSensitive(@s[1],@OldPattern[1],Length(S),Length(OldPattern),Matches, rfReplaceAll in Flags);
  723. end;
  724. MatchesCount:=Length(Matches);
  725. aCount:=MatchesCount;
  726. //Create room enougth for the result string
  727. SetLength(Result,Length(S)-OldPatternSize*MatchesCount+NewPatternSize*MatchesCount);
  728. MatchIndex:=1;
  729. MatchTarget:=1;
  730. //Matches[x] are 0 based offsets
  731. for MatchInternal := 0 to Pred(MatchesCount) do begin
  732. //Copy information up to next match
  733. AdvanceIndex:=Matches[MatchInternal]+1-MatchIndex;
  734. if AdvanceIndex>0 then begin
  735. move(S[MatchIndex],Result[MatchTarget],AdvanceIndex);
  736. inc(MatchTarget,AdvanceIndex);
  737. inc(MatchIndex,AdvanceIndex);
  738. end;
  739. //Copy the new replace information string
  740. if NewPatternSize>0 then begin
  741. move(NewPattern[1],Result[MatchTarget],NewPatternSize);
  742. inc(MatchTarget,NewPatternSize);
  743. end;
  744. inc(MatchIndex,OldPatternSize);
  745. end;
  746. if MatchTarget<=Length(Result) then begin
  747. //Add remain data at the end of source.
  748. move(S[MatchIndex],Result[MatchTarget],Length(Result)-MatchTarget+1);
  749. end;
  750. end;
  751. function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; Algorithm: TStringReplaceAlgorithm): string;
  752. Var
  753. C : Integer;
  754. begin
  755. Result:=StringReplace(S, OldPattern, NewPattern, Flags,C,Algorithm);
  756. end;
  757. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
  758. begin
  759. Case Algorithm of
  760. sraDefault : Result:=sysutils.StringReplace(S,OldPattern,NewPattern,Flags,aCount);
  761. sraManySmall : Result:=StringReplaceFast(S,OldPattern,NewPattern,Flags,aCount);
  762. sraBoyerMoore : Result:=StringReplaceBoyerMoore(S,OldPattern,NewPattern,Flags,aCount);
  763. end;
  764. end;
  765. {$IF SIZEOF(CHAR)=1}
  766. function StringReplace(const S, OldPattern, NewPattern: unicodestring; Flags: TReplaceFlags): unicodestring;
  767. begin
  768. Result:=sysutils.StringReplace(S,OldPattern,NewPattern,Flags);
  769. end;
  770. function StringReplace(const S, OldPattern, NewPattern: widestring; Flags: TReplaceFlags): widestring;
  771. begin
  772. Result:=sysutils.StringReplace(S,OldPattern,NewPattern,Flags);
  773. end;
  774. {$ENDIF}
  775. function FindMatchesBoyerMooreCaseSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean
  776. ): Boolean;
  777. Var
  778. I : SizeInt;
  779. begin
  780. Result:=FindMatchesBoyerMooreCaseSensitive(PAnsiChar(S),PAnsiChar(OldPattern),Length(S),Length(OldPattern),aMatches,aMatchAll);
  781. For I:=0 to pred(Length(AMatches)) do
  782. Inc(AMatches[i]);
  783. end;
  784. function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean
  785. ): Boolean;
  786. Var
  787. I : SizeInt;
  788. begin
  789. Result:=FindMatchesBoyerMooreCaseInSensitive(PAnsiChar(S),PAnsiChar(OldPattern),Length(S),Length(OldPattern),aMatches,aMatchAll);
  790. For I:=0 to pred(Length(AMatches)) do
  791. Inc(AMatches[i]);
  792. end;
  793. { ---------------------------------------------------------------------
  794. Possibly Exception raising functions
  795. ---------------------------------------------------------------------}
  796. function Hex2Dec(const S: string): Longint;
  797. var
  798. HexStr: string;
  799. begin
  800. if Pos('$',S)=0 then
  801. HexStr:='$'+ S
  802. else
  803. HexStr:=S;
  804. Result:=StrToInt(HexStr);
  805. end;
  806. function Hex2Dec64(const S: string): int64;
  807. var
  808. HexStr: string;
  809. begin
  810. if Pos('$',S)=0 then
  811. HexStr:='$'+ S
  812. else
  813. HexStr:=S;
  814. Result:=StrToInt64(HexStr);
  815. end;
  816. {
  817. We turn off implicit exceptions, since these routines are tested, and it
  818. saves 20% codesize (and some speed) and don't throw exceptions, except maybe
  819. heap related. If they don't, that is consider a bug.
  820. In the future, be wary with routines that use strtoint, floating point
  821. and/or format() derivatives. And check every divisor for 0.
  822. }
  823. {$IMPLICITEXCEPTIONS OFF}
  824. { ---------------------------------------------------------------------
  825. Case insensitive search/replace
  826. ---------------------------------------------------------------------}
  827. function AnsiResemblesText(const AText, AOther: AnsiString): Boolean;
  828. begin
  829. if Assigned(AnsiResemblesProc) then
  830. Result:=AnsiResemblesProc(AText,AOther)
  831. else
  832. Result:=False;
  833. end;
  834. function AnsiContainsText(const AText, ASubText: AnsiString): Boolean;
  835. begin
  836. AnsiContainsText:=AnsiPos(AnsiUppercase(ASubText),AnsiUppercase(AText))>0;
  837. end;
  838. function AnsiStartsText(const ASubText, AText: AnsiString): Boolean;
  839. begin
  840. Result := (ASubText = '') or AnsiSameText(LeftStr(AText, Length(ASubText)), ASubText);
  841. end;
  842. function AnsiEndsText(const ASubText, AText: AnsiString): Boolean;
  843. begin
  844. Result := (ASubText = '') or AnsiSameText(RightStr(AText, Length(ASubText)), ASubText);
  845. end;
  846. function AnsiEndsText(const ASubText, AText: UnicodeString): Boolean;
  847. begin
  848. Result := (ASubText = '') or SameText(RightStr(AText, Length(ASubText)), ASubText);
  849. end;
  850. function StartsText(const ASubText, AText: String): Boolean; inline;
  851. begin
  852. Result := AnsiStartsText(ASubText, AText);
  853. end;
  854. function EndsText(const ASubText, AText: string): Boolean;
  855. begin
  856. Result := AnsiEndsText(ASubText, AText);
  857. end;
  858. function ResemblesText(const AText, AOther: string): Boolean;
  859. begin
  860. if Assigned(ResemblesProc) then
  861. Result := ResemblesProc(AText, AOther)
  862. else
  863. Result := False;
  864. end;
  865. function ContainsText(const AText, ASubText: string): Boolean;
  866. begin
  867. Result := AnsiContainsText(AText, ASubText);
  868. end;
  869. function MatchText(const AText: Ansistring; const AValues: array of Ansistring): Boolean;
  870. begin
  871. Result := AnsiMatchText(AText, AValues);
  872. end;
  873. function IndexText(const AText: Ansistring; const AValues: array of Ansistring): Integer;
  874. begin
  875. Result := AnsiIndexText(AText, AValues);
  876. end;
  877. function ContainsStr(const AText, ASubText: String): Boolean;
  878. begin
  879. Result := AnsiContainsStr(AText, ASubText);
  880. end;
  881. function MatchStr(const AText: Ansistring; const AValues: array of Ansistring): Boolean;
  882. begin
  883. Result := AnsiMatchStr(AText, AValues);
  884. end;
  885. function IndexStr(const AText: AnsiString; const AValues: array of AnsiString): Integer;
  886. begin
  887. Result := AnsiIndexStr(AText, AValues);
  888. end;
  889. function AnsiReplaceText(const AText, AFromText, AToText: Ansistring): Ansistring;
  890. begin
  891. Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll,rfIgnoreCase]);
  892. end;
  893. function AnsiMatchText(const AText: Ansistring; const AValues: array of AnsiString): Boolean;
  894. begin
  895. Result:=(AnsiIndexText(AText,AValues)<>-1)
  896. end;
  897. function AnsiIndexText(const AText: AnsiString; const AValues: array of Ansistring): Integer;
  898. begin
  899. for Result := Low(AValues) to High(AValues) do
  900. if AnsiSameText(AValues[Result], AText) then
  901. Exit;
  902. Result := -1;
  903. end;
  904. { ---------------------------------------------------------------------
  905. Case sensitive search/replace
  906. ---------------------------------------------------------------------}
  907. function AnsiContainsStr(const AText, ASubText: Ansistring): Boolean;
  908. begin
  909. Result := AnsiPos(ASubText,AText)>0;
  910. end;
  911. function AnsiContainsStr(const AText, ASubText: Unicodestring): Boolean;
  912. begin
  913. Result := AnsiPos(ASubText,AText)>0;
  914. end;
  915. function AnsiStartsStr(const ASubText, AText: AnsiString): Boolean;
  916. begin
  917. Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText);
  918. end;
  919. function AnsiStartsStr(const ASubText, AText: UnicodeString): Boolean;
  920. begin
  921. Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText);
  922. end;
  923. function AnsiEndsStr(const ASubText, AText: AnsiString): Boolean;
  924. begin
  925. Result := (ASubText = '') or (RightStr(AText, Length(ASubText)) = ASubText);
  926. end;
  927. function AnsiEndsStr(const ASubText, AText: UnicodeString): Boolean;
  928. begin
  929. Result := (ASubText = '') or (RightStr(AText, Length(ASubText)) = ASubText);
  930. end;
  931. function StartsStr(const ASubText, AText: string): Boolean;
  932. begin
  933. if (Length(AText) >= Length(ASubText)) and (ASubText <> '') then
  934. Result := StrLComp(PChar(ASubText), PChar(AText), Length(ASubText)) = 0
  935. else
  936. Result := (AsubText='');
  937. end;
  938. function EndsStr(const ASubText, AText: string): Boolean;
  939. begin
  940. if Length(AText) >= Length(ASubText) then
  941. Result := StrLComp(PChar(ASubText),
  942. PChar(AText) + Length(AText) - Length(ASubText), Length(ASubText)) = 0
  943. else
  944. Result := False;
  945. end;
  946. function AnsiReplaceStr(const AText, AFromText, AToText: AnsiString): AnsiString;
  947. begin
  948. Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll]);
  949. end;
  950. function AnsiMatchStr(const AText: AnsiString; const AValues: array of AnsiString): Boolean;
  951. begin
  952. Result:=AnsiIndexStr(AText,Avalues)<>-1;
  953. end;
  954. function AnsiIndexStr(const AText: AnsiString; const AValues: array of AnsiString): Integer;
  955. var
  956. i : longint;
  957. begin
  958. result:=-1;
  959. if (high(AValues)=-1) or (High(AValues)>MaxInt) Then
  960. Exit;
  961. for i:=low(AValues) to High(Avalues) do
  962. if (avalues[i]=AText) Then
  963. exit(i); // make sure it is the first val.
  964. end;
  965. function MatchStr(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  966. begin
  967. Result := IndexStr(AText,AValues) <> -1;
  968. end;
  969. function MatchText(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  970. begin
  971. Result := IndexText(AText,AValues) <> -1;
  972. end;
  973. function IndexStr(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  974. var
  975. i: longint;
  976. begin
  977. Result := -1;
  978. if (high(AValues) = -1) or (High(AValues) > MaxInt) Then
  979. Exit;
  980. for i := low(AValues) to High(Avalues) do
  981. if (avalues[i] = AText) Then
  982. exit(i); // make sure it is the first val.
  983. end;
  984. function IndexText(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  985. var
  986. i : Integer;
  987. begin
  988. Result:=-1;
  989. if (high(AValues)=-1) or (High(AValues)>MaxInt) Then
  990. Exit;
  991. for i:=low(AValues) to High(Avalues) do
  992. if UnicodeCompareText(avalues[i],atext)=0 Then
  993. exit(i); // make sure it is the first val.
  994. end;
  995. operator in(const AText: AnsiString; const AValues: array of AnsiString): Boolean;
  996. begin
  997. Result := AnsiIndexStr(AText,AValues) <>-1;
  998. end;
  999. operator in(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  1000. begin
  1001. Result := IndexStr(AText,AValues) <> -1;
  1002. end;
  1003. { ---------------------------------------------------------------------
  1004. Playthingies
  1005. ---------------------------------------------------------------------}
  1006. function DupeString(const AText: string; ACount: Integer): string;
  1007. var
  1008. Len, BitIndex, Rp: SizeInt;
  1009. begin
  1010. Len := Length(AText);
  1011. if (Len = 0) or (ACount <= 0) then
  1012. Exit('');
  1013. if ACount = 1 then
  1014. Exit(AText);
  1015. SetLength(Result, ACount * Len);
  1016. Rp := 0;
  1017. // Build up ACount repeats by duplicating the string built so far and adding another AText if corresponding ACount binary digit is 1.
  1018. // For example, ACount = 5 = %101 will, starting from the empty string:
  1019. // (1) duplicate (count = 0), add AText (count = 1)
  1020. // (0) duplicate (count = 2)
  1021. // (1) duplicate (count = 4), add AText (count = 5)
  1022. for BitIndex := BsrDWord(ACount) downto 0 do
  1023. begin
  1024. Move(Pointer(Result)^, PAnsiChar(Pointer(Result))[Rp], Rp * SizeOf(AnsiChar));
  1025. Inc(Rp, Rp);
  1026. if ACount shr BitIndex and 1 <> 0 then
  1027. begin
  1028. Move(Pointer(AText)^, PAnsiChar(Pointer(Result))[Rp], Len * SizeOf(AnsiChar));
  1029. Inc(Rp, Len);
  1030. end;
  1031. end;
  1032. end;
  1033. function ReverseString(const AText: string): string;
  1034. var
  1035. i,j : SizeInt;
  1036. begin
  1037. setlength(result,length(atext));
  1038. i:=1; j:=length(atext);
  1039. while (i<=j) do
  1040. begin
  1041. result[i]:=atext[j-i+1];
  1042. inc(i);
  1043. end;
  1044. end;
  1045. function AnsiReverseString(const AText: AnsiString): AnsiString;
  1046. begin
  1047. Result:=ReverseString(AText);
  1048. end;
  1049. function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
  1050. var i,j,k : SizeUInt;
  1051. begin
  1052. j:=length(ASubText);
  1053. i:=length(AText);
  1054. if AStart>i then
  1055. aStart:=i+1;
  1056. k:=i+1-AStart;
  1057. if ALength> k then
  1058. ALength:=k;
  1059. SetLength(Result,i+j-ALength);
  1060. move (AText[1],result[1],AStart-1);
  1061. move (ASubText[1],result[AStart],j);
  1062. move (AText[AStart+ALength], Result[AStart+j],i+1-AStart-ALength);
  1063. end;
  1064. function RandomFrom(const AValues: array of string): string;
  1065. begin
  1066. if high(AValues)=-1 then exit('');
  1067. result:=Avalues[random(High(AValues)+1)];
  1068. end;
  1069. function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string): string;
  1070. begin
  1071. if avalue then
  1072. result:=atrue
  1073. else
  1074. result:=afalse;
  1075. end;
  1076. Function IfThen(AValue: Boolean; const ATrue: TStringDynArray; const AFalse: TStringDynArray = nil): TStringDynArray; overload;
  1077. begin
  1078. if avalue then
  1079. result:=atrue
  1080. else
  1081. result:=afalse;
  1082. end;
  1083. function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: AnsiChar): Integer;
  1084. {
  1085. NaturalCompareBase compares strings in a collated order and
  1086. so numbers are sorted too. It sorts like this:
  1087. 01
  1088. 001
  1089. 0001
  1090. and
  1091. 0
  1092. 00
  1093. 000
  1094. 000_A
  1095. 000_B
  1096. in a intuitive order.
  1097. }
  1098. var
  1099. Num1, Num2: double;
  1100. pStr1, pStr2: PAnsiChar;
  1101. Len1, Len2: SizeInt;
  1102. TextLen1, TextLen2: SizeInt;
  1103. TextStr1: string = '';
  1104. TextStr2: string = '';
  1105. i: SizeInt;
  1106. j: SizeInt;
  1107. function Sign(const AValue: sizeint): integer;inline;
  1108. begin
  1109. If Avalue<0 then
  1110. Result:=-1
  1111. else If Avalue>0 then
  1112. Result:=1
  1113. else
  1114. Result:=0;
  1115. end;
  1116. function IsNumber(ch: AnsiChar): boolean;
  1117. begin
  1118. Result := ch in ['0'..'9'];
  1119. end;
  1120. function GetInteger(var pch: PAnsiChar; var Len: sizeint): double;
  1121. begin
  1122. Result := 0;
  1123. while (pch^ <> #0) and IsNumber(pch^) do
  1124. begin
  1125. Result := Result * 10 + Ord(pch^) - Ord('0');
  1126. Inc(Len);
  1127. Inc(pch);
  1128. end;
  1129. end;
  1130. procedure GetChars;
  1131. begin
  1132. TextLen1 := 0;
  1133. while not ((pStr1 + TextLen1)^ in ['0'..'9']) and ((pStr1 + TextLen1)^ <> #0) do
  1134. Inc(TextLen1);
  1135. SetLength(TextStr1, TextLen1);
  1136. i := 1;
  1137. j := 0;
  1138. while i <= TextLen1 do
  1139. begin
  1140. TextStr1[i] := (pStr1 + j)^;
  1141. Inc(i);
  1142. Inc(j);
  1143. end;
  1144. TextLen2 := 0;
  1145. while not ((pStr2 + TextLen2)^ in ['0'..'9']) and ((pStr2 + TextLen2)^ <> #0) do
  1146. Inc(TextLen2);
  1147. SetLength(TextStr2, TextLen2);
  1148. i := 1;
  1149. j := 0;
  1150. while i <= TextLen2 do
  1151. begin
  1152. TextStr2[i] := (pStr2 + j)^;
  1153. Inc(i);
  1154. Inc(j);
  1155. end;
  1156. end;
  1157. begin
  1158. if (Str1 <> '') and (Str2 <> '') then
  1159. begin
  1160. pStr1 := PAnsiChar(Str1);
  1161. pStr2 := PAnsiChar(Str2);
  1162. Result := 0;
  1163. while not ((pStr1^ = #0) or (pStr2^ = #0)) do
  1164. begin
  1165. TextLen1 := 1;
  1166. TextLen2 := 1;
  1167. Len1 := 0;
  1168. Len2 := 0;
  1169. while (pStr1^ = ' ') do
  1170. begin
  1171. Inc(pStr1);
  1172. Inc(Len1);
  1173. end;
  1174. while (pStr2^ = ' ') do
  1175. begin
  1176. Inc(pStr2);
  1177. Inc(Len2);
  1178. end;
  1179. if IsNumber(pStr1^) and IsNumber(pStr2^) then
  1180. begin
  1181. Num1 := GetInteger(pStr1, Len1);
  1182. Num2 := GetInteger(pStr2, Len2);
  1183. if Num1 < Num2 then
  1184. Result := -1
  1185. else if Num1 > Num2 then
  1186. Result := 1
  1187. else
  1188. begin
  1189. Result := Sign(Len1 - Len2);
  1190. end;
  1191. Dec(pStr1);
  1192. Dec(pStr2);
  1193. end
  1194. else
  1195. begin
  1196. GetChars;
  1197. if TextStr1 <> TextStr2 then
  1198. Result := WideCompareText(UTF8Decode(TextStr1), UTF8Decode(TextStr2))
  1199. else
  1200. Result := 0;
  1201. end;
  1202. if Result <> 0 then
  1203. Break;
  1204. Inc(pStr1, TextLen1);
  1205. Inc(pStr2, TextLen2);
  1206. end;
  1207. end;
  1208. Num1 := Length(Str1);
  1209. Num2 := Length(Str2);
  1210. if (Result = 0) and (Num1 <> Num2) then
  1211. begin
  1212. if Num1 < Num2 then
  1213. Result := -1
  1214. else
  1215. Result := 1;
  1216. end;
  1217. end;
  1218. function SplitString(const S, Delimiters: string): TRTLStringDynArray;
  1219. Var
  1220. a : Array of Char;
  1221. I : Integer;
  1222. begin
  1223. SetLength(A,Length(Delimiters));
  1224. For I:=1 to Length(Delimiters) do
  1225. A[I-1]:=Delimiters[i];
  1226. Result := S.Split(A);
  1227. end;
  1228. function NaturalCompareText (const S1 , S2 : string ): Integer ;
  1229. begin
  1230. Result := NaturalCompareText(S1, S2,
  1231. DefaultFormatSettings.DecimalSeparator,
  1232. DefaultFormatSettings.ThousandSeparator);
  1233. end;
  1234. { ---------------------------------------------------------------------
  1235. VB emulations.
  1236. ---------------------------------------------------------------------}
  1237. function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1238. begin
  1239. Result:=Copy(AText,1,ACount);
  1240. end;
  1241. function RightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1242. var j,l:SizeInt;
  1243. begin
  1244. l:=length(atext);
  1245. j:=ACount;
  1246. if j>l then j:=l;
  1247. Result:=Copy(AText,l-j+1,j);
  1248. end;
  1249. function MidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;
  1250. begin
  1251. if (ACount=0) or (AStart>length(atext)) then
  1252. exit('');
  1253. Result:=Copy(AText,AStart,ACount);
  1254. end;
  1255. function LeftBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;
  1256. begin
  1257. Result:=LeftStr(AText,AByteCount);
  1258. end;
  1259. function RightBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;
  1260. begin
  1261. Result:=RightStr(Atext,AByteCount);
  1262. end;
  1263. function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: SizeInt): AnsiString;
  1264. begin
  1265. Result:=MidStr(AText,AByteStart,AByteCount);
  1266. end;
  1267. function AnsiLeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1268. begin
  1269. Result := copy(AText,1,ACount);
  1270. end;
  1271. function AnsiRightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1272. begin
  1273. Result := copy(AText,length(AText)-ACount+1,ACount);
  1274. end;
  1275. function AnsiMidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;
  1276. begin
  1277. Result:=Copy(AText,AStart,ACount);
  1278. end;
  1279. function LeftStr(const AText: WideString; const ACount: SizeInt): WideString;
  1280. begin
  1281. Result:=Copy(AText,1,ACount);
  1282. end;
  1283. function RightStr(const AText: WideString; const ACount: SizeInt): WideString;
  1284. var
  1285. j,l:SizeInt;
  1286. begin
  1287. l:=length(atext);
  1288. j:=ACount;
  1289. if j>l then j:=l;
  1290. Result:=Copy(AText,l-j+1,j);
  1291. end;
  1292. function MidStr(const AText: WideString; const AStart, ACount: SizeInt): WideString;
  1293. begin
  1294. Result:=Copy(AText,AStart,ACount);
  1295. end;
  1296. { ---------------------------------------------------------------------
  1297. Extended search and replace
  1298. ---------------------------------------------------------------------}
  1299. type
  1300. TEqualFunction = function (const a,b : AnsiChar) : boolean;
  1301. function EqualWithCase (const a,b : AnsiChar) : boolean;
  1302. begin
  1303. result := (a = b);
  1304. end;
  1305. function EqualWithoutCase (const a,b : AnsiChar) : boolean;
  1306. begin
  1307. result := (lowerCase(a) = lowerCase(b));
  1308. end;
  1309. function IsWholeWord (bufstart, bufend, wordstart, wordend : PAnsiChar) : boolean;
  1310. begin
  1311. // Check start
  1312. result := ((wordstart = bufstart) or ((wordstart-1)^ in worddelimiters)) and
  1313. // Check end
  1314. ((wordend = bufend) or ((wordend+1)^ in worddelimiters));
  1315. end;
  1316. function SearchDown(buf,aStart,endchar:PAnsiChar; SearchString:string;
  1317. Equals : TEqualFunction; WholeWords:boolean) : PAnsiChar;
  1318. var Found : boolean;
  1319. s, c : PAnsiChar;
  1320. begin
  1321. result := aStart;
  1322. Found := false;
  1323. while not Found and (result <= endchar) do
  1324. begin
  1325. // Search first letter
  1326. while (result <= endchar) and not Equals(result^,SearchString[1]) do
  1327. inc (result);
  1328. // Check if following is searchstring
  1329. c := result;
  1330. s := @(Searchstring[1]);
  1331. Found := true;
  1332. while (c <= endchar) and (s^ <> #0) and Found do
  1333. begin
  1334. Found := Equals(c^, s^);
  1335. inc (c);
  1336. inc (s);
  1337. end;
  1338. if s^ <> #0 then
  1339. Found := false;
  1340. // Check if it is a word
  1341. if Found and WholeWords then
  1342. Found := IsWholeWord(buf,endchar,result,c-1);
  1343. if not found then
  1344. inc (result);
  1345. end;
  1346. if not Found then
  1347. result := nil;
  1348. end;
  1349. function SearchUp(buf,aStart,endchar:PAnsiChar; SearchString:string;
  1350. equals : TEqualFunction; WholeWords:boolean) : PAnsiChar;
  1351. var Found : boolean;
  1352. s, c, l : PAnsiChar;
  1353. begin
  1354. result := aStart;
  1355. Found := false;
  1356. l := @(SearchString[length(SearchString)]);
  1357. while not Found and (result >= buf) do
  1358. begin
  1359. // Search last letter
  1360. while (result >= buf) and not Equals(result^,l^) do
  1361. dec (result);
  1362. // Check if before is searchstring
  1363. c := result;
  1364. s := l;
  1365. Found := true;
  1366. while (c >= buf) and (s >= @SearchString[1]) and Found do
  1367. begin
  1368. Found := Equals(c^, s^);
  1369. dec (c);
  1370. dec (s);
  1371. end;
  1372. if (s >= @(SearchString[1])) then
  1373. Found := false;
  1374. // Check if it is a word
  1375. if Found and WholeWords then
  1376. Found := IsWholeWord(buf,endchar,c+1,result);
  1377. if found then
  1378. result := c+1
  1379. else
  1380. dec (result);
  1381. end;
  1382. if not Found then
  1383. result := nil;
  1384. end;
  1385. //function SearchDown(buf,aStart,endchar:PAnsiChar; SearchString:string; equal : TEqualFunction; WholeWords:boolean) : PAnsiChar;
  1386. function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String; Options: TStringSearchOptions
  1387. ): PAnsiChar;
  1388. var
  1389. equal : TEqualFunction;
  1390. begin
  1391. SelStart := SelStart + SelLength;
  1392. if (SearchString = '') or (SelStart > BufLen) or (SelStart < 0) then
  1393. result := nil
  1394. else
  1395. begin
  1396. if soMatchCase in Options then
  1397. Equal := @EqualWithCase
  1398. else
  1399. Equal := @EqualWithoutCase;
  1400. if soDown in Options then
  1401. result := SearchDown(buf,buf+SelStart,Buf+(BufLen-1), SearchString, Equal, (soWholeWord in Options))
  1402. else
  1403. result := SearchUp(buf,buf+SelStart,Buf+(Buflen-1), SearchString, Equal, (soWholeWord in Options));
  1404. end;
  1405. end;
  1406. function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String): PAnsiChar; // ; Options: TStringSearchOptions = [soDown]
  1407. begin
  1408. Result:=SearchBuf(Buf,BufLen,SelStart,SelLength,SearchString,[soDown]);
  1409. end;
  1410. function PosEx(const SubStr, S: AnsiString; Offset: SizeUint): SizeInt;
  1411. var
  1412. i,MaxLen, SubLen : SizeInt;
  1413. SubFirst: AnsiChar;
  1414. pc : PAnsiChar;
  1415. begin
  1416. PosEx:=0;
  1417. SubLen := Length(SubStr);
  1418. if (SubLen > 0) and (Offset > 0) and (Offset <= Cardinal(Length(S))) then
  1419. begin
  1420. MaxLen := Length(S)- SubLen;
  1421. SubFirst := SubStr[1];
  1422. i := indexbyte(S[Offset],Length(S) - Offset + 1, Byte(SubFirst));
  1423. while (i >= 0) and ((i + sizeint(Offset) - 1) <= MaxLen) do
  1424. begin
  1425. pc := @S[i+SizeInt(Offset)];
  1426. //we know now that pc^ = SubFirst, because indexbyte returned a value > -1
  1427. if (CompareByte(Substr[1],pc^,SubLen) = 0) then
  1428. begin
  1429. PosEx := i + SizeInt(Offset);
  1430. Exit;
  1431. end;
  1432. //point Offset to next AnsiChar in S
  1433. Offset := sizeuint(i) + Offset + 1;
  1434. i := indexbyte(S[Offset],Length(S) - Offset + 1, Byte(SubFirst));
  1435. end;
  1436. end;
  1437. end;
  1438. function PosEx(c: AnsiChar; const S: Ansistring; Offset: SizeUint): SizeInt;
  1439. var
  1440. p,Len : SizeInt;
  1441. begin
  1442. Len := length(S);
  1443. if (Offset < 1) or (Offset > SizeUInt(Length(S))) then exit(0);
  1444. Len := length(S);
  1445. p := indexbyte(S[Offset],Len-offset+1,Byte(c));
  1446. if (p < 0) then
  1447. PosEx := 0
  1448. else
  1449. PosEx := p + sizeint(Offset);
  1450. end;
  1451. function PosEx(const SubStr, S: Ansistring): SizeInt; // Offset: Cardinal = 1
  1452. begin
  1453. posex:=posex(substr,s,1);
  1454. end;
  1455. function PosEx(const SubStr, S: UnicodeString; Offset: SizeUint): SizeInt;
  1456. var
  1457. i,MaxLen, SubLen : SizeInt;
  1458. SubFirst: WideChar;
  1459. pc : pwidechar;
  1460. begin
  1461. PosEx:=0;
  1462. SubLen := Length(SubStr);
  1463. if (SubLen > 0) and (Offset > 0) and (Offset <= Cardinal(Length(S))) then
  1464. begin
  1465. MaxLen := Length(S)- SubLen;
  1466. SubFirst := SubStr[1];
  1467. i := indexword(S[Offset],Length(S) - Offset + 1, Word(SubFirst));
  1468. while (i >= 0) and ((i + sizeint(Offset) - 1) <= MaxLen) do
  1469. begin
  1470. pc := @S[i+SizeInt(Offset)];
  1471. //we know now that pc^ = SubFirst, because indexbyte returned a value > -1
  1472. if (CompareWord(Substr[1],pc^,SubLen) = 0) then
  1473. begin
  1474. PosEx := i + SizeInt(Offset);
  1475. Exit;
  1476. end;
  1477. //point Offset to next AnsiChar in S
  1478. Offset := sizeuint(i) + Offset + 1;
  1479. i := indexword(S[Offset],Length(S) - Offset + 1, Word(SubFirst));
  1480. end;
  1481. end;
  1482. end;
  1483. function PosEx(c: WideChar; const S: UnicodeString; Offset: SizeUint): SizeInt;
  1484. var
  1485. Len,p : SizeInt;
  1486. begin
  1487. Len := length(S);
  1488. if (Offset < 1) or (Offset > SizeUInt(Length(S))) then exit(0);
  1489. Len := length(S);
  1490. p := indexword(S[Offset],Len-offset+1,Word(c));
  1491. if (p < 0) then
  1492. PosEx := 0
  1493. else
  1494. PosEx := p + sizeint(Offset);
  1495. end;
  1496. function PosEx(const SubStr, S: UnicodeString): Sizeint; // Offset: Cardinal = 1
  1497. begin
  1498. PosEx:=PosEx(SubStr,S,1);
  1499. end;
  1500. function StringsReplace(const S: AnsiString; OldPattern, NewPattern: array of AnsiString; Flags: TReplaceFlags): string;
  1501. var pc,pcc,lastpc : PAnsiChar;
  1502. strcount : integer;
  1503. ResStr,
  1504. CompStr : string;
  1505. Found : Boolean;
  1506. sc : sizeint;
  1507. begin
  1508. sc := length(OldPattern);
  1509. if sc <> length(NewPattern) then
  1510. raise exception.Create(SErrAmountStrings);
  1511. dec(sc);
  1512. if rfIgnoreCase in Flags then
  1513. begin
  1514. CompStr:=AnsiUpperCase(S);
  1515. for strcount := 0 to sc do
  1516. OldPattern[strcount] := AnsiUpperCase(OldPattern[strcount]);
  1517. end
  1518. else
  1519. CompStr := s;
  1520. ResStr := '';
  1521. pc := @CompStr[1];
  1522. pcc := @s[1];
  1523. lastpc := pc+Length(S);
  1524. while pc < lastpc do
  1525. begin
  1526. Found := False;
  1527. for strcount := 0 to sc do
  1528. begin
  1529. if (length(OldPattern[strcount])>0) and
  1530. (OldPattern[strcount][1]=pc^) and
  1531. (Length(OldPattern[strcount]) <= (lastpc-pc)) and
  1532. (CompareByte(OldPattern[strcount][1],pc^,Length(OldPattern[strcount]))=0) then
  1533. begin
  1534. ResStr := ResStr + NewPattern[strcount];
  1535. pc := pc+Length(OldPattern[strcount]);
  1536. pcc := pcc+Length(OldPattern[strcount]);
  1537. Found := true;
  1538. end
  1539. end;
  1540. if not found then
  1541. begin
  1542. ResStr := ResStr + pcc^;
  1543. inc(pc);
  1544. inc(pcc);
  1545. end
  1546. else if not (rfReplaceAll in Flags) then
  1547. begin
  1548. ResStr := ResStr + StrPas(pcc);
  1549. break;
  1550. end;
  1551. end;
  1552. Result := ResStr;
  1553. end;
  1554. { ---------------------------------------------------------------------
  1555. Delphi compat
  1556. ---------------------------------------------------------------------}
  1557. function ReplaceStr(const AText, AFromText, AToText: string): string;
  1558. begin
  1559. result:=AnsiReplaceStr(AText, AFromText, AToText);
  1560. end;
  1561. function ReplaceText(const AText, AFromText, AToText: string): string;
  1562. begin
  1563. result:=AnsiReplaceText(AText, AFromText, AToText);
  1564. end;
  1565. { ---------------------------------------------------------------------
  1566. Soundex Functions.
  1567. ---------------------------------------------------------------------}
  1568. Const
  1569. SScore : array[1..255] of AnsiChar =
  1570. ('0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 1..32
  1571. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 33..64
  1572. '0','1','2','3','0','1','2','i','0','2','2','4','5','5','0','1','2','6','2','3','0','1','i','2','i','2', // 65..90
  1573. '0','0','0','0','0','0', // 91..96
  1574. '0','1','2','3','0','1','2','i','0','2','2','4','5','5','0','1','2','6','2','3','0','1','i','2','i','2', // 97..122
  1575. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 123..154
  1576. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 155..186
  1577. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 187..218
  1578. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 219..250
  1579. '0','0','0','0','0'); // 251..255
  1580. function Soundex(const AText: string; ALength: TSoundexLength): string;
  1581. Var
  1582. S,PS : AnsiChar;
  1583. I,L : SizeInt;
  1584. begin
  1585. Result:='';
  1586. PS:=#0;
  1587. If Length(AText)>0 then
  1588. begin
  1589. Result:=Upcase(AText[1]);
  1590. I:=2;
  1591. L:=Length(AText);
  1592. While (I<=L) and (Length(Result)<ALength) do
  1593. begin
  1594. S:=SScore[Ord(AText[i])];
  1595. If Not (S in ['0','i',PS]) then
  1596. Result:=Result+S;
  1597. If (S<>'i') then
  1598. PS:=S;
  1599. Inc(I);
  1600. end;
  1601. end;
  1602. L:=Length(Result);
  1603. If (L<ALength) then
  1604. Result:=Result+StringOfChar('0',Alength-L);
  1605. end;
  1606. function Soundex(const AText: string): string; // ; ALength: TSoundexLength = 4
  1607. begin
  1608. Result:=Soundex(AText,4);
  1609. end;
  1610. Const
  1611. Ord0 = Ord('0');
  1612. OrdA = Ord('A');
  1613. function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
  1614. var
  1615. SE: string;
  1616. I: SizeInt;
  1617. begin
  1618. Result:=-1;
  1619. SE:=Soundex(AText,ALength);
  1620. If Length(SE)>0 then
  1621. begin
  1622. Result:=Ord(SE[1])-OrdA;
  1623. if ALength > 1 then
  1624. begin
  1625. Result:=Result*26+(Ord(SE[2])-Ord0);
  1626. for I:=3 to ALength do
  1627. Result:=(Ord(SE[I])-Ord0)+Result*7;
  1628. end;
  1629. Result:=ALength+Result*9;
  1630. end;
  1631. end;
  1632. function SoundexInt(const AText: string): Integer; //; ALength: TSoundexIntLength = 4
  1633. begin
  1634. Result:=SoundexInt(AText,4);
  1635. end;
  1636. function DecodeSoundexInt(AValue: Integer): string;
  1637. var
  1638. I, Len: Integer;
  1639. begin
  1640. Result := '';
  1641. Len := AValue mod 9;
  1642. AValue := AValue div 9;
  1643. for I:=Len downto 3 do
  1644. begin
  1645. Result:=Chr(Ord0+(AValue mod 7))+Result;
  1646. AValue:=AValue div 7;
  1647. end;
  1648. if Len>1 then
  1649. begin
  1650. Result:=Chr(Ord0+(AValue mod 26))+Result;
  1651. AValue:=AValue div 26;
  1652. end;
  1653. Result:=Chr(OrdA+AValue)+Result;
  1654. end;
  1655. function SoundexWord(const AText: string): Word;
  1656. Var
  1657. S : String;
  1658. begin
  1659. S:=SoundEx(Atext,4);
  1660. Result:=Ord(S[1])-OrdA;
  1661. Result:=Result*26+ord(S[2])-48;
  1662. Result:=Result*7+ord(S[3])-48;
  1663. Result:=Result*7+ord(S[4])-48;
  1664. end;
  1665. function DecodeSoundexWord(AValue: Word): string;
  1666. begin
  1667. Result := Chr(Ord0+ (AValue mod 7));
  1668. AValue := AValue div 7;
  1669. Result := Chr(Ord0+ (AValue mod 7)) + Result;
  1670. AValue := AValue div 7;
  1671. Result := IntToStr(AValue mod 26) + Result;
  1672. AValue := AValue div 26;
  1673. Result := Chr(OrdA+AValue) + Result;
  1674. end;
  1675. function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;
  1676. begin
  1677. Result:=Soundex(AText,ALength)=Soundex(AOther,ALength);
  1678. end;
  1679. function SoundexSimilar(const AText, AOther: string): Boolean; //; ALength: TSoundexLength = 4
  1680. begin
  1681. Result:=SoundexSimilar(AText,AOther,4);
  1682. end;
  1683. function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;
  1684. begin
  1685. Result:=AnsiCompareStr(Soundex(AText,ALength),Soundex(AOther,ALength));
  1686. end;
  1687. function SoundexCompare(const AText, AOther: string): Integer; //; ALength: TSoundexLength = 4
  1688. begin
  1689. Result:=SoundexCompare(AText,AOther,4);
  1690. end;
  1691. function SoundexProc(const AText, AOther: string): Boolean;
  1692. begin
  1693. Result:=SoundexSimilar(AText,AOther);
  1694. end;
  1695. { ---------------------------------------------------------------------
  1696. RxStrUtils-like functions.
  1697. ---------------------------------------------------------------------}
  1698. function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
  1699. var
  1700. i,l: SizeInt;
  1701. begin
  1702. l:=Length(S);
  1703. i:=1;
  1704. Result:=True;
  1705. while Result and (i<=l) do
  1706. begin
  1707. Result:=(S[i] in EmptyChars);
  1708. Inc(i);
  1709. end;
  1710. end;
  1711. function DelSpace(const S: string): string;
  1712. begin
  1713. Result:=DelChars(S,' ');
  1714. end;
  1715. function DelChars(const S: string; Chr: AnsiChar): string;
  1716. var
  1717. I,J: SizeInt;
  1718. begin
  1719. Result:=S;
  1720. I:=Length(Result);
  1721. While I>0 do
  1722. begin
  1723. if Result[I]=Chr then
  1724. begin
  1725. J:=I-1;
  1726. While (J>0) and (Result[J]=Chr) do
  1727. Dec(j);
  1728. Delete(Result,J+1,I-J);
  1729. I:=J+1;
  1730. end;
  1731. dec(I);
  1732. end;
  1733. end;
  1734. function DelChars(const S: string; Chars: TSysCharSet): string;
  1735. var
  1736. I,J: SizeInt;
  1737. begin
  1738. Result:=S;
  1739. if Chars=[] then exit;
  1740. I:=Length(Result);
  1741. While I>0 do
  1742. begin
  1743. if Result[I]in Chars then
  1744. begin
  1745. J:=I-1;
  1746. While (J>0) and (Result[J]in Chars) do
  1747. Dec(j);
  1748. Delete(Result,J+1,I-J);
  1749. I:=J+1;
  1750. end;
  1751. dec(I);
  1752. end;
  1753. end;
  1754. function DelSpace1(const S: string): string;
  1755. var
  1756. I,J: SizeInt;
  1757. begin
  1758. Result:=S;
  1759. I:=Length(Result);
  1760. While I>0 do
  1761. begin
  1762. if Result[I]=#32 then
  1763. begin
  1764. J:=I-1;
  1765. While (J>0) and (Result[J]=#32) do
  1766. Dec(j);
  1767. Inc(J);
  1768. if I<>J then
  1769. begin
  1770. Delete(Result,J+1,I-J);
  1771. I:=J+1;
  1772. end;
  1773. end;
  1774. dec(I);
  1775. end;
  1776. end;
  1777. function Tab2Space(const S: string; Numb: Byte): string;
  1778. var
  1779. I: SizeInt;
  1780. begin
  1781. I:=1;
  1782. Result:=S;
  1783. while I <= Length(Result) do
  1784. if Result[I]<>Chr(9) then
  1785. inc(I)
  1786. else
  1787. begin
  1788. Result[I]:=' ';
  1789. If (Numb>1) then
  1790. Insert(StringOfChar(' ',Numb-1),Result,I);
  1791. Inc(I,Numb);
  1792. end;
  1793. end;
  1794. function NPos(const C: string; S: string; N: Integer): SizeInt;
  1795. var
  1796. i,p,k: SizeInt;
  1797. begin
  1798. Result:=0;
  1799. if N<1 then
  1800. Exit;
  1801. k:=0;
  1802. i:=1;
  1803. Repeat
  1804. p:=pos(C,S);
  1805. Inc(k,p);
  1806. if p>0 then
  1807. delete(S,1,p);
  1808. Inc(i);
  1809. Until (i>n) or (p=0);
  1810. If (P>0) then
  1811. Result:=K;
  1812. end;
  1813. function AddChar(C: AnsiChar; const S: string; N: Integer): string;
  1814. Var
  1815. l : SizeInt;
  1816. begin
  1817. Result:=S;
  1818. l:=Length(Result);
  1819. if l<N then
  1820. Result:=StringOfChar(C,N-l)+Result;
  1821. end;
  1822. function AddCharR(C: AnsiChar; const S: string; N: Integer): string;
  1823. Var
  1824. l : SizeInt;
  1825. begin
  1826. Result:=S;
  1827. l:=Length(Result);
  1828. if l<N then
  1829. Result:=Result+StringOfChar(C,N-l);
  1830. end;
  1831. function PadRight(const S: string; N: Integer): string;inline;
  1832. begin
  1833. Result:=AddCharR(' ',S,N);
  1834. end;
  1835. function PadLeft(const S: string; N: Integer): string;inline;
  1836. begin
  1837. Result:=AddChar(' ',S,N);
  1838. end;
  1839. function Copy2Symb(const S: string; Symb: AnsiChar): string;
  1840. var
  1841. p: SizeInt;
  1842. begin
  1843. p:=Pos(Symb,S);
  1844. if p=0 then
  1845. p:=Length(S)+1;
  1846. Result:=Copy(S,1,p-1);
  1847. end;
  1848. function Copy2SymbDel(var S: string; Symb: AnsiChar): string;
  1849. var
  1850. p: SizeInt;
  1851. begin
  1852. p:=Pos(Symb,S);
  1853. if p=0 then
  1854. begin
  1855. result:=s;
  1856. s:='';
  1857. end
  1858. else
  1859. begin
  1860. Result:=Copy(S,1,p-1);
  1861. delete(s,1,p);
  1862. end;
  1863. end;
  1864. function Copy2Space(const S: string): string;inline;
  1865. begin
  1866. Result:=Copy2Symb(S,' ');
  1867. end;
  1868. function Copy2SpaceDel(var S: string): string;inline;
  1869. begin
  1870. Result:=Copy2SymbDel(S,' ');
  1871. end;
  1872. function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
  1873. var
  1874. P,PE : PAnsiChar;
  1875. begin
  1876. Result:=AnsiLowerCase(S);
  1877. P:=PAnsiChar(pointer(Result));
  1878. PE:=P+Length(Result);
  1879. while (P<PE) do
  1880. begin
  1881. while (P<PE) and (P^ in WordDelims) do
  1882. inc(P);
  1883. if (P<PE) then
  1884. P^:=UpCase(P^);
  1885. while (P<PE) and not (P^ in WordDelims) do
  1886. inc(P);
  1887. end;
  1888. end;
  1889. function WordCount(const S: string; const WordDelims: TSysCharSet): SizeInt;
  1890. var
  1891. P,PE : PAnsiChar;
  1892. begin
  1893. Result:=0;
  1894. P:=PAnsiChar(pointer(S));
  1895. PE:=P+Length(S);
  1896. while (P<PE) do
  1897. begin
  1898. while (P<PE) and (P^ in WordDelims) do
  1899. Inc(P);
  1900. if (P<PE) then
  1901. inc(Result);
  1902. while (P<PE) and not (P^ in WordDelims) do
  1903. inc(P);
  1904. end;
  1905. end;
  1906. function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): SizeInt;
  1907. var
  1908. PS,P,PE : PAnsiChar;
  1909. Count: Integer;
  1910. begin
  1911. Result:=0;
  1912. Count:=0;
  1913. PS:=PAnsiChar(pointer(S));
  1914. PE:=PS+Length(S);
  1915. P:=PS;
  1916. while (P<PE) and (Count<>N) do
  1917. begin
  1918. while (P<PE) and (P^ in WordDelims) do
  1919. inc(P);
  1920. if (P<PE) then
  1921. inc(Count);
  1922. if (Count<>N) then
  1923. while (P<PE) and not (P^ in WordDelims) do
  1924. inc(P)
  1925. else
  1926. Result:=(P-PS)+1;
  1927. end;
  1928. end;
  1929. function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
  1930. var
  1931. i: SizeInt;
  1932. begin
  1933. Result:=ExtractWordPos(N,S,WordDelims,i);
  1934. end;
  1935. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: Integer): string;
  1936. var
  1937. i,j,l: SizeInt;
  1938. begin
  1939. j:=0;
  1940. i:=WordPosition(N, S, WordDelims);
  1941. if (I>High(Integer)) then
  1942. begin
  1943. Result:='';
  1944. Pos:=-1;
  1945. Exit;
  1946. end;
  1947. Pos:=i;
  1948. if (i<>0) then
  1949. begin
  1950. j:=i;
  1951. l:=Length(S);
  1952. while (j<=L) and not (S[j] in WordDelims) do
  1953. inc(j);
  1954. end;
  1955. SetLength(Result,j-i);
  1956. If ((j-i)>0) then
  1957. Move(S[i],Result[1],j-i);
  1958. end;
  1959. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  1960. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; Out Pos: SizeInt): string;
  1961. var
  1962. i,j,l: SizeInt;
  1963. begin
  1964. j:=0;
  1965. i:=WordPosition(N, S, WordDelims);
  1966. Pos:=i;
  1967. if (i<>0) then
  1968. begin
  1969. j:=i;
  1970. l:=Length(S);
  1971. while (j<=L) and not (S[j] in WordDelims) do
  1972. inc(j);
  1973. end;
  1974. SetLength(Result,j-i);
  1975. If ((j-i)>0) then
  1976. Move(S[i],Result[1],j-i);
  1977. end;
  1978. {$ENDIF}
  1979. function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
  1980. var
  1981. w,i,l,len: SizeInt;
  1982. begin
  1983. w:=0;
  1984. i:=1;
  1985. l:=0;
  1986. len:=Length(S);
  1987. SetLength(Result, 0);
  1988. while (i<=len) and (w<>N) do
  1989. begin
  1990. if s[i] in Delims then
  1991. inc(w)
  1992. else
  1993. begin
  1994. if (N-1)=w then
  1995. begin
  1996. inc(l);
  1997. SetLength(Result,l);
  1998. Result[L]:=S[i];
  1999. end;
  2000. end;
  2001. inc(i);
  2002. end;
  2003. end;
  2004. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  2005. function ExtractSubstr(const S: string; var Pos: SizeInt; const Delims: TSysCharSet): string;
  2006. var
  2007. i,l: SizeInt;
  2008. begin
  2009. i:=Pos;
  2010. l:=Length(S);
  2011. while (i<=l) and not (S[i] in Delims) do
  2012. inc(i);
  2013. Result:=Copy(S,Pos,i-Pos);
  2014. while (i<=l) and (S[i] in Delims) do
  2015. inc(i);
  2016. Pos:=i;
  2017. end;
  2018. {$ENDIF}
  2019. function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
  2020. var
  2021. i,l: SizeInt;
  2022. begin
  2023. i:=Pos;
  2024. l:=Length(S);
  2025. while (i<=l) and not (S[i] in Delims) do
  2026. inc(i);
  2027. Result:=Copy(S,Pos,i-Pos);
  2028. while (i<=l) and (S[i] in Delims) do
  2029. inc(i);
  2030. if I>MaxInt then
  2031. Pos:=MaxInt
  2032. else
  2033. Pos:=i;
  2034. end;
  2035. function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
  2036. var
  2037. i,Count : SizeInt;
  2038. begin
  2039. Result:=False;
  2040. Count:=WordCount(S, WordDelims);
  2041. I:=1;
  2042. While (Not Result) and (I<=Count) do
  2043. begin
  2044. Result:=ExtractWord(i,S,WordDelims)=W;
  2045. Inc(i);
  2046. end;
  2047. end;
  2048. function Numb2USA(const S: string): string;
  2049. var
  2050. i, NA: Integer;
  2051. begin
  2052. i:=Length(S);
  2053. Result:=S;
  2054. NA:=0;
  2055. while (i > 0) do begin
  2056. if ((Length(Result) - i + 1 - NA) mod 3 = 0) and (i <> 1) then
  2057. begin
  2058. insert(',', Result, i);
  2059. inc(NA);
  2060. end;
  2061. Dec(i);
  2062. end;
  2063. end;
  2064. function PadCenter(const S: string; Len: SizeInt): string;
  2065. begin
  2066. if Length(S)<Len then
  2067. begin
  2068. Result:=StringOfChar(' ',(Len div 2) -(Length(S) div 2))+S;
  2069. Result:=Result+StringOfChar(' ',Len-Length(Result));
  2070. end
  2071. else
  2072. Result:=S;
  2073. end;
  2074. function Dec2Numb(N: Longint; Len, Base: Byte): string;
  2075. var
  2076. C: Integer;
  2077. Number: Longint;
  2078. begin
  2079. if N=0 then
  2080. Result:='0'
  2081. else
  2082. begin
  2083. Number:=N;
  2084. Result:='';
  2085. while Number>0 do
  2086. begin
  2087. C:=Number mod Base;
  2088. if C>9 then
  2089. C:=C+55
  2090. else
  2091. C:=C+48;
  2092. Result:=Chr(C)+Result;
  2093. Number:=Number div Base;
  2094. end;
  2095. end;
  2096. if (Result<>'') then
  2097. Result:=AddChar('0',Result,Len);
  2098. end;
  2099. function Numb2Dec(S: string; Base: Byte): Longint;
  2100. var
  2101. i, P: sizeint;
  2102. begin
  2103. i:=Length(S);
  2104. Result:=0;
  2105. S:=UpperCase(S);
  2106. P:=1;
  2107. while (i>=1) do
  2108. begin
  2109. if (S[i]>'@') then
  2110. Result:=Result+(Ord(S[i])-55)*P
  2111. else
  2112. Result:=Result+(Ord(S[i])-48)*P;
  2113. Dec(i);
  2114. P:=P*Base;
  2115. end;
  2116. end;
  2117. function RomanToIntDontCare(const S: String): Longint;
  2118. {This was the original implementation of RomanToInt,
  2119. it is internally used in TryRomanToInt when Strictness = rcsDontCare}
  2120. const
  2121. RomanChars = ['C','D','I','L','M','V','X'];
  2122. RomanValues : array['C'..'X'] of Word
  2123. = (100,500,0,0,0,0,1,0,0,50,1000,0,0,0,0,0,0,0,0,5,0,10);
  2124. var
  2125. index, Next: AnsiChar;
  2126. i,l: SizeInt;
  2127. Negative: Boolean;
  2128. begin
  2129. Result:=0;
  2130. i:=0;
  2131. Negative:=(Length(S)>0) and (S[1]='-');
  2132. if Negative then
  2133. inc(i);
  2134. l:=Length(S);
  2135. while (i<l) do
  2136. begin
  2137. inc(i);
  2138. index:=UpCase(S[i]);
  2139. if index in RomanChars then
  2140. begin
  2141. if Succ(i)<=l then
  2142. Next:=UpCase(S[i+1])
  2143. else
  2144. Next:=#0;
  2145. if (Next in RomanChars) and (RomanValues[index]<RomanValues[Next]) then
  2146. begin
  2147. inc(Result, RomanValues[Next]);
  2148. Dec(Result, RomanValues[index]);
  2149. inc(i);
  2150. end
  2151. else
  2152. inc(Result, RomanValues[index]);
  2153. end
  2154. else
  2155. begin
  2156. Result:=0;
  2157. Exit;
  2158. end;
  2159. end;
  2160. if Negative then
  2161. Result:=-Result;
  2162. end;
  2163. { TryRomanToInt: try to convert a roman numeral to an integer
  2164. Parameters:
  2165. S: Roman numeral (like: 'MCMXXII')
  2166. N: Integer value of S (only meaningfull if the function succeeds)
  2167. Stricness: controls how strict the parsing of S is
  2168. - rcsStrict:
  2169. * Follow common subtraction rules
  2170. - only 1 preceding subtraction character allowed: IX = 9, but IIX <> 8
  2171. - from M you can only subtract C
  2172. - from D you can only subtract C
  2173. - from C you can only subtract X
  2174. - from L you can only subtract X
  2175. - from X you can only subtract I
  2176. - from V you can only subtract I
  2177. * The numeral is parsed in "groups" (first M's, then D's etc.), the next group to be parsed
  2178. must always be of a lower denomination than the previous one.
  2179. Example: 'MMDCCXX' is allowed but 'MMCCXXDD' is not
  2180. * There can only ever be 3 consecutive M's, C's, X's or I's
  2181. * There can only ever be 1 D, 1 L and 1 V
  2182. * After IX or IV there can be no more characters
  2183. * Negative numbers are not supported
  2184. // As a consequence the maximum allowed Roman numeral is MMMCMXCIX = 3999, also N can never become 0 (zero)
  2185. - rcsRelaxed: Like rcsStrict but with the following exceptions:
  2186. * An infinite number of (leading) M's is allowed
  2187. * Up to 4 consecutive M's, C's, X's and I's are allowed
  2188. // So this is allowed: 'MMMMMMCXIIII' = 6124
  2189. - rcsDontCare:
  2190. * no checking on the order of "groups" is done
  2191. * there are no restrictions on the number of consecutive chars
  2192. * negative numbers are supported
  2193. * an empty string as input will return True and N will be 0
  2194. * invalid input will return false
  2195. // for backwards comatibility: it supports rather ludicrous input like '-IIIMIII' -> -(2+(1000-1)+3)=-1004
  2196. }
  2197. function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
  2198. var
  2199. i, Len: SizeInt;
  2200. Terminated: Boolean;
  2201. begin
  2202. Result := (False);
  2203. S := UpperCase(S); //don't use AnsiUpperCase please
  2204. Len := Length(S);
  2205. if (Strictness = rcsDontCare) then
  2206. begin
  2207. N := RomanToIntDontCare(S);
  2208. if (N = 0) then
  2209. begin
  2210. Result := (Len = 0);
  2211. end
  2212. else
  2213. Result := True;
  2214. Exit;
  2215. end;
  2216. if (Len = 0) then
  2217. begin
  2218. Result:=true;
  2219. N:=0;
  2220. Exit;
  2221. end;
  2222. i := 1;
  2223. N := 0;
  2224. Terminated := False;
  2225. //leading M's
  2226. while (i <= Len) and ((Strictness <> rcsStrict) or (i < 4)) and (S[i] = 'M') do
  2227. begin
  2228. //writeln('TryRomanToInt: Found 1000');
  2229. Inc(i);
  2230. N := N + 1000;
  2231. end;
  2232. //then CM or or CD or D or (C, CC, CCC, CCCC)
  2233. if (i <= Len) and (S[i] = 'D') then
  2234. begin
  2235. //writeln('TryRomanToInt: Found 500');
  2236. Inc(i);
  2237. N := N + 500;
  2238. end
  2239. else if (i + 1 <= Len) and (S[i] = 'C') then
  2240. begin
  2241. if (S[i+1] = 'M') then
  2242. begin
  2243. //writeln('TryRomanToInt: Found 900');
  2244. Inc(i,2);
  2245. N := N + 900;
  2246. end
  2247. else if (S[i+1] = 'D') then
  2248. begin
  2249. //writeln('TryRomanToInt: Found 400');
  2250. Inc(i,2);
  2251. N := N + 400;
  2252. end;
  2253. end ;
  2254. //next max 4 or 3 C's, depending on Strictness
  2255. if (i <= Len) and (S[i] = 'C') then
  2256. begin
  2257. //find max 4 C's
  2258. //writeln('TryRomanToInt: Found 100');
  2259. Inc(i);
  2260. N := N + 100;
  2261. if (i <= Len) and (S[i] = 'C') then
  2262. begin
  2263. //writeln('TryRomanToInt: Found 100');
  2264. Inc(i);
  2265. N := N + 100;
  2266. end;
  2267. if (i <= Len) and (S[i] = 'C') then
  2268. begin
  2269. //writeln('TryRomanToInt: Found 100');
  2270. Inc(i);
  2271. N := N + 100;
  2272. end;
  2273. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'C') then
  2274. begin
  2275. //writeln('TryRomanToInt: Found 100');
  2276. Inc(i);
  2277. N := N + 100;
  2278. end;
  2279. end;
  2280. //then XC or XL
  2281. if (i + 1 <= Len) and (S[i] = 'X') then
  2282. begin
  2283. if (S[i+1] = 'C') then
  2284. begin
  2285. //writeln('TryRomanToInt: Found 90');
  2286. Inc(i,2);
  2287. N := N + 90;
  2288. end
  2289. else if (S[i+1] = 'L') then
  2290. begin
  2291. //writeln('TryRomanToInt: Found 40');
  2292. Inc(i,2);
  2293. N := N + 40;
  2294. end;
  2295. end;
  2296. //then L
  2297. if (i <= Len) and (S[i] = 'L') then
  2298. begin
  2299. //writeln('TryRomanToInt: Found 50');
  2300. Inc(i);
  2301. N := N + 50;
  2302. end;
  2303. //then (X, xx, xxx, xxxx)
  2304. if (i <= Len) and (S[i] = 'X') then
  2305. begin
  2306. //find max 3 or 4 X's, depending on Strictness
  2307. //writeln('TryRomanToInt: Found 10');
  2308. Inc(i);
  2309. N := N + 10;
  2310. if (i <= Len) and (S[i] = 'X') then
  2311. begin
  2312. //writeln('TryRomanToInt: Found 10');
  2313. Inc(i);
  2314. N := N + 10;
  2315. end;
  2316. if (i <= Len) and (S[i] = 'X') then
  2317. begin
  2318. //writeln('TryRomanToInt: Found 10');
  2319. Inc(i);
  2320. N := N + 10;
  2321. end;
  2322. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'X') then
  2323. begin
  2324. //writeln('TryRomanToInt: Found 10');
  2325. Inc(i);
  2326. N := N + 10;
  2327. end;
  2328. end;
  2329. //then IX or IV
  2330. if (i + 1 <= Len) and (S[i] = 'I') then
  2331. begin
  2332. if (S[i+1] = 'X') then
  2333. begin
  2334. Terminated := (True);
  2335. //writeln('TryRomanToInt: Found 9');
  2336. Inc(i,2);
  2337. N := N + 9;
  2338. end
  2339. else if (S[i+1] = 'V') then
  2340. begin
  2341. Terminated := (True);
  2342. //writeln('TryRomanToInt: Found 4');
  2343. Inc(i,2);
  2344. N := N + 4;
  2345. end;
  2346. end;
  2347. //then V
  2348. if (not Terminated) and (i <= Len) and (S[i] = 'V') then
  2349. begin
  2350. //writeln('TryRomanToInt: Found 5');
  2351. Inc(i);
  2352. N := N + 5;
  2353. end;
  2354. //then I
  2355. if (not Terminated) and (i <= Len) and (S[i] = 'I') then
  2356. begin
  2357. Terminated := (True);
  2358. //writeln('TryRomanToInt: Found 1');
  2359. Inc(i);
  2360. N := N + 1;
  2361. //Find max 2 or 3 closing I's, depending on strictness
  2362. if (i <= Len) and (S[i] = 'I') then
  2363. begin
  2364. //writeln('TryRomanToInt: Found 1');
  2365. Inc(i);
  2366. N := N + 1;
  2367. end;
  2368. if (i <= Len) and (S[i] = 'I') then
  2369. begin
  2370. //writeln('TryRomanToInt: Found 1');
  2371. Inc(i);
  2372. N := N + 1;
  2373. end;
  2374. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'I') then
  2375. begin
  2376. //writeln('TryRomanToInt: Found 1');
  2377. Inc(i);
  2378. N := N + 1;
  2379. end;
  2380. end;
  2381. //writeln('TryRomanToInt: Len = ',Len,' i = ',i);
  2382. Result := (i > Len);
  2383. //if Result then writeln('TryRomanToInt: N = ',N);
  2384. end;
  2385. function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  2386. begin
  2387. if not TryRomanToInt(S, Result, Strictness) then
  2388. raise EConvertError.CreateFmt(SInvalidRomanNumeral,[S]);
  2389. end;
  2390. function RomanToIntDef(const S: String; const ADefault: Longint;
  2391. Strictness: TRomanConversionStrictness): Longint;
  2392. begin
  2393. if not TryRomanToInt(S, Result, Strictness) then
  2394. Result := ADefault;
  2395. end;
  2396. function IntToRoman(Value: Longint): string;
  2397. const
  2398. Arabics : Array[1..13] of Integer
  2399. = (1,4,5,9,10,40,50,90,100,400,500,900,1000);
  2400. Romans : Array[1..13] of String
  2401. = ('I','IV','V','IX','X','XL','L','XC','C','CD','D','CM','M');
  2402. var
  2403. i: Integer;
  2404. begin
  2405. Result:='';
  2406. for i:=13 downto 1 do
  2407. while (Value >= Arabics[i]) do
  2408. begin
  2409. Value:=Value-Arabics[i];
  2410. Result:=Result+Romans[i];
  2411. end;
  2412. end;
  2413. function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
  2414. var endpos : integer;
  2415. p,p2:PChar;
  2416. k: integer;
  2417. begin
  2418. Result:='';
  2419. if (Digits>32) then
  2420. Digits:=32;
  2421. if (spaces=0) then
  2422. begin
  2423. result:=inttobin(value,digits);
  2424. exit;
  2425. end;
  2426. endpos:=digits+ (digits-1) div spaces;
  2427. setlength(result,endpos);
  2428. p:=@result[endpos];
  2429. p2:=@result[1];
  2430. k:=spaces;
  2431. while (p>=p2) do
  2432. begin
  2433. if k=0 then
  2434. begin
  2435. p^:=' ';
  2436. dec(p);
  2437. k:=spaces;
  2438. end;
  2439. p^:=chr(48+(cardinal(value) and 1));
  2440. value:=cardinal(value) shr 1;
  2441. dec(p);
  2442. dec(k);
  2443. end;
  2444. end;
  2445. function IntToBin(Value: Longint; Digits: Integer): string;
  2446. var p,p2 : PChar;
  2447. begin
  2448. result:='';
  2449. if digits<=0 then exit;
  2450. setlength(result,digits);
  2451. p:=PChar(pointer(@result[digits]));
  2452. p2:=PChar(pointer(@result[1]));
  2453. // typecasts because we want to keep intto* delphi compat and take an integer
  2454. while (p>=p2) and (cardinal(value)>0) do
  2455. begin
  2456. p^:=chr(48+(cardinal(value) and 1));
  2457. value:=cardinal(value) shr 1;
  2458. dec(p);
  2459. end;
  2460. digits:=p-p2+1;
  2461. if digits>0 then
  2462. fillchar(result[1],digits,#48);
  2463. end;
  2464. function intToBin(Value: int64; Digits:integer): string;
  2465. var p,p2 : PChar;
  2466. begin
  2467. result:='';
  2468. if digits<=0 then exit;
  2469. setlength(result,digits);
  2470. p:=PChar(pointer(@result[digits]));
  2471. p2:=PChar(pointer(@result[1]));
  2472. // typecasts because we want to keep intto* delphi compat and take a signed val
  2473. // and avoid warnings
  2474. while (p>=p2) and (qword(value)>0) do
  2475. begin
  2476. p^:=chr(48+(cardinal(value) and 1));
  2477. value:=qword(value) shr 1;
  2478. dec(p);
  2479. end;
  2480. digits:=p-p2+1;
  2481. if digits>0 then
  2482. fillchar(result[1],digits,#48);
  2483. end;
  2484. function FindPart(const HelpWilds, InputStr: string): SizeInt;
  2485. var
  2486. Diff, i, J: SizeInt;
  2487. begin
  2488. Result:=0;
  2489. i:=Pos('?',HelpWilds);
  2490. if (i=0) then
  2491. Result:=Pos(HelpWilds, inputStr)
  2492. else
  2493. begin
  2494. Diff:=Length(inputStr) - Length(HelpWilds);
  2495. for i:=0 to Diff do
  2496. begin
  2497. for J:=1 to Length(HelpWilds) do
  2498. if (inputStr[i + J] = HelpWilds[J]) or (HelpWilds[J] = '?') then
  2499. begin
  2500. if (J=Length(HelpWilds)) then
  2501. begin
  2502. Result:=i+1;
  2503. Exit;
  2504. end;
  2505. end
  2506. else
  2507. Break;
  2508. end;
  2509. end;
  2510. end;
  2511. Function isMatch(level : integer;inputstr,wilds : string; CWild, CinputWord: SizeInt;MaxInputword,maxwilds : SizeInt; Out EOS : Boolean) : Boolean;
  2512. function WildisQuestionmark : boolean;
  2513. begin
  2514. Result:=CWild <= MaxWilds;
  2515. if Result then
  2516. Result:= Wilds[CWild]='?';
  2517. end;
  2518. function WildisStar : boolean;
  2519. begin
  2520. Result:=CWild <= MaxWilds;
  2521. if Result then
  2522. Result:= Wilds[CWild]='*';
  2523. end;
  2524. begin
  2525. EOS:=False;
  2526. Result:=True;
  2527. repeat
  2528. if WildisStar then { handling of '*' }
  2529. begin
  2530. inc(CWild);
  2531. if CWild>MaxWilds then
  2532. begin
  2533. EOS:=true;
  2534. exit;
  2535. end;
  2536. while WildisQuestionmark do { equal to '?' }
  2537. begin
  2538. { goto next letter }
  2539. inc(CWild);
  2540. inc(CinputWord);
  2541. end;
  2542. { increase until a match }
  2543. Repeat
  2544. while (CinputWord <= MaxinputWord) and (CWild <= MaxWilds) and (inputStr[CinputWord]<>Wilds[CWild]) do
  2545. inc(CinputWord);
  2546. Result:=isMatch(Level+1,inputstr,wilds,CWild, CinputWord,MaxInputword,maxwilds,EOS);
  2547. if not Result then
  2548. Inc(cInputWord);
  2549. Until Result or (CinputWord>=MaxinputWord);
  2550. if Result and EOS then
  2551. Exit;
  2552. Continue;
  2553. end;
  2554. if WildisQuestionmark then { equal to '?' }
  2555. begin
  2556. { goto next letter }
  2557. inc(CWild);
  2558. inc(CinputWord);
  2559. Continue;
  2560. end;
  2561. if (CinputWord>MaxinputWord) or (CWild > MaxWilds) or (inputStr[CinputWord] = Wilds[CWild]) then { equal letters }
  2562. begin
  2563. { goto next letter }
  2564. inc(CWild);
  2565. inc(CinputWord);
  2566. Continue;
  2567. end;
  2568. Result:=false;
  2569. Exit;
  2570. until (CinputWord > MaxinputWord) or (CWild > MaxWilds);
  2571. { no completed evaluation, we need to check what happened }
  2572. if (CinputWord <= MaxinputWord) or (CWild < MaxWilds) then
  2573. Result:=false
  2574. else if (CWild>Maxwilds) then
  2575. EOS:=False
  2576. else
  2577. begin
  2578. EOS:=Wilds[CWild]='*';
  2579. if not EOS then
  2580. Result:=False;
  2581. end
  2582. end;
  2583. function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
  2584. var
  2585. i: SizeInt;
  2586. MaxinputWord, MaxWilds: SizeInt; { Length of inputStr and Wilds }
  2587. eos : Boolean;
  2588. begin
  2589. Result:=true;
  2590. if Wilds = inputStr then
  2591. Exit;
  2592. { delete '**', because '**' = '*' }
  2593. i:=Pos('**', Wilds);
  2594. while i > 0 do
  2595. begin
  2596. Delete(Wilds, i, 1);
  2597. i:=Pos('**', Wilds);
  2598. end;
  2599. if Wilds = '*' then { for fast end, if Wilds only '*' }
  2600. Exit;
  2601. MaxinputWord:=Length(inputStr);
  2602. MaxWilds:=Length(Wilds);
  2603. if (MaxWilds = 0) or (MaxinputWord = 0) then
  2604. begin
  2605. Result:=false;
  2606. Exit;
  2607. end;
  2608. if ignoreCase then { upcase all letters }
  2609. begin
  2610. inputStr:=AnsiUpperCase(inputStr);
  2611. Wilds:=AnsiUpperCase(Wilds);
  2612. end;
  2613. Result:=isMatch(1,inputStr,wilds,1,1,MaxinputWord, MaxWilds,EOS);
  2614. end;
  2615. function XorString(const Key, Src: ShortString): ShortString;
  2616. var
  2617. i: SizeInt;
  2618. begin
  2619. Result:=Src;
  2620. if Length(Key) > 0 then
  2621. for i:=1 to Length(Src) do
  2622. Result[i]:=Chr(Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Ord(Src[i]));
  2623. end;
  2624. function XorEncode(const Key, Source: Ansistring): Ansistring;
  2625. var
  2626. i: Integer;
  2627. C: Byte;
  2628. begin
  2629. Result:='';
  2630. for i:=1 to Length(Source) do
  2631. begin
  2632. if Length(Key) > 0 then
  2633. C:=Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Byte(Source[i])
  2634. else
  2635. C:=Byte(Source[i]);
  2636. Result:=Result+AnsiLowerCase(intToHex(C, 2));
  2637. end;
  2638. end;
  2639. function XorDecode(const Key, Source: Ansistring): Ansistring;
  2640. var
  2641. i: Integer;
  2642. C: AnsiChar;
  2643. begin
  2644. Result:='';
  2645. for i:=0 to Length(Source) div 2 - 1 do
  2646. begin
  2647. C:=Chr(StrTointDef('$' + Copy(Source, (i * 2) + 1, 2), Ord(' ')));
  2648. if Length(Key) > 0 then
  2649. C:=Chr(Byte(Key[1 + (i mod Length(Key))]) xor Byte(C));
  2650. Result:=Result + C;
  2651. end;
  2652. end;
  2653. function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
  2654. var
  2655. i: Integer;
  2656. S: string;
  2657. begin
  2658. i:=1;
  2659. Result:='';
  2660. while (Result='') and (i<=ParamCount) do
  2661. begin
  2662. S:=ParamStr(i);
  2663. if (SwitchChars=[]) or ((S[1] in SwitchChars) and (Length(S) > 1)) and
  2664. (AnsiCompareText(Copy(S,2,Length(S)-1),Switch)=0) then
  2665. begin
  2666. inc(i);
  2667. if i<=ParamCount then
  2668. Result:=ParamStr(i);
  2669. end;
  2670. inc(i);
  2671. end;
  2672. end;
  2673. function RPosEx(C: AnsiChar; const S: AnsiString; offs: cardinal): SizeInt;
  2674. var I : SizeUInt;
  2675. p,p2: PAnsiChar;
  2676. Begin
  2677. I:=Length(S);
  2678. If (I<>0) and (offs<=i) Then
  2679. begin
  2680. p:=@s[offs];
  2681. p2:=@s[1];
  2682. while (p2<=p) and (p^<>c) do dec(p);
  2683. RPosEx:=(p-p2)+1;
  2684. end
  2685. else
  2686. RPosEX:=0;
  2687. End;
  2688. function RPos(c: AnsiChar; const S: AnsiString): SizeInt;
  2689. var I : SizeInt;
  2690. p,p2: PAnsiChar;
  2691. Begin
  2692. I:=Length(S);
  2693. If I<>0 Then
  2694. begin
  2695. p:=@s[i];
  2696. p2:=@s[1];
  2697. while (p2<=p) and (p^<>c) do dec(p);
  2698. i:=p-p2+1;
  2699. end;
  2700. RPos:=i;
  2701. End;
  2702. function RPos(const Substr: AnsiString; const Source: AnsiString): SizeInt;
  2703. var
  2704. MaxLen,llen : SizeInt;
  2705. c : AnsiChar;
  2706. pc,pc2 : PAnsiChar;
  2707. begin
  2708. rPos:=0;
  2709. llen:=Length(SubStr);
  2710. maxlen:=length(source);
  2711. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  2712. begin
  2713. // i:=maxlen;
  2714. pc:=@source[maxlen];
  2715. pc2:=@source[llen-1];
  2716. c:=substr[llen];
  2717. while pc>=pc2 do
  2718. begin
  2719. if (c=pc^) and
  2720. (CompareChar(Substr[1],PAnsiChar(pc-llen+1)^,Length(SubStr))=0) then
  2721. begin
  2722. rPos:=PAnsiChar(pc-llen+1)-PAnsiChar(@source[1])+1;
  2723. exit;
  2724. end;
  2725. dec(pc);
  2726. end;
  2727. end;
  2728. end;
  2729. function RPosEx(const Substr: AnsiString; const Source: AnsiString; offs: cardinal): SizeInt;
  2730. var
  2731. MaxLen,llen : SizeInt;
  2732. c : AnsiChar;
  2733. pc,pc2 : PAnsiChar;
  2734. begin
  2735. rPosex:=0;
  2736. llen:=Length(SubStr);
  2737. maxlen:=length(source);
  2738. if SizeInt(offs)<maxlen then maxlen:=offs;
  2739. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  2740. begin
  2741. // i:=maxlen;
  2742. pc:=@source[maxlen];
  2743. pc2:=@source[llen-1];
  2744. c:=substr[llen];
  2745. while pc>=pc2 do
  2746. begin
  2747. if (c=pc^) and
  2748. (CompareChar(Substr[1],PAnsiChar(pc-llen+1)^,Length(SubStr))=0) then
  2749. begin
  2750. rPosex:=PAnsiChar(pc-llen+1)-PAnsiChar(@source[1])+1;
  2751. exit;
  2752. end;
  2753. dec(pc);
  2754. end;
  2755. end;
  2756. end;
  2757. function RPosEx(C: unicodechar; const S: UnicodeString; offs: cardinal): SizeInt;
  2758. var I : SizeUInt;
  2759. p,p2: PUnicodeChar;
  2760. Begin
  2761. I:=Length(S);
  2762. If (I<>0) and (offs<=i) Then
  2763. begin
  2764. p:=@s[offs];
  2765. p2:=@s[1];
  2766. while (p2<=p) and (p^<>c) do dec(p);
  2767. RPosEx:=(p-p2)+1;
  2768. end
  2769. else
  2770. RPosEX:=0;
  2771. End;
  2772. function RPos(c: Unicodechar; const S: UnicodeString): SizeInt;
  2773. var I : SizeInt;
  2774. p,p2: pUnicodeChar;
  2775. Begin
  2776. I:=Length(S);
  2777. If I<>0 Then
  2778. begin
  2779. p:=@s[i];
  2780. p2:=@s[1];
  2781. while (p2<=p) and (p^<>c) do dec(p);
  2782. i:=p-p2+1;
  2783. end;
  2784. RPos:=i;
  2785. End;
  2786. function RPos(const Substr: UnicodeString; const Source: UnicodeString): SizeInt;
  2787. var
  2788. MaxLen,llen : SizeInt;
  2789. c : Unicodechar;
  2790. pc,pc2 : PUnicodechar;
  2791. begin
  2792. rPos:=0;
  2793. llen:=Length(SubStr);
  2794. maxlen:=length(source);
  2795. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  2796. begin
  2797. pc:=@source[maxlen];
  2798. pc2:=@source[llen-1];
  2799. c:=substr[llen];
  2800. while pc>=pc2 do
  2801. begin
  2802. if (c=pc^) and
  2803. (CompareWord(Substr[1],punicodechar(pc-llen+1)^,Length(SubStr))=0) then
  2804. begin
  2805. rPos:=punicodechar(pc-llen+1)-punicodechar(@source[1])+1;
  2806. exit;
  2807. end;
  2808. dec(pc);
  2809. end;
  2810. end;
  2811. end;
  2812. function RPosEx(const Substr: UnicodeString; const Source: UnicodeString; offs: cardinal): SizeInt;
  2813. var
  2814. MaxLen,llen : SizeInt;
  2815. c : unicodechar;
  2816. pc,pc2 : punicodechar;
  2817. begin
  2818. rPosex:=0;
  2819. llen:=Length(SubStr);
  2820. maxlen:=length(source);
  2821. if SizeInt(offs)<maxlen then maxlen:=offs;
  2822. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  2823. begin
  2824. pc:=@source[maxlen];
  2825. pc2:=@source[llen-1];
  2826. c:=substr[llen];
  2827. while pc>=pc2 do
  2828. begin
  2829. if (c=pc^) and
  2830. (Compareword(Substr[1],punicodechar(pc-llen+1)^,Length(SubStr))=0) then
  2831. begin
  2832. rPosex:=punicodechar(pc-llen+1)-punicodechar(@source[1])+1;
  2833. exit;
  2834. end;
  2835. dec(pc);
  2836. end;
  2837. end;
  2838. end;
  2839. procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer);
  2840. var
  2841. i : longint;
  2842. begin
  2843. for i:=0 to BinBufSize-1 do
  2844. begin
  2845. HexValue[0]:=HexDigits[((Ord(BinValue[i]) shr 4))];
  2846. HexValue[1]:=HexDigits[((Ord(BinValue[i]) and 15))];
  2847. Inc(HexValue,2);
  2848. end;
  2849. end;
  2850. procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer);
  2851. var
  2852. i : longint;
  2853. begin
  2854. for i:=0 to BinBufSize-1 do
  2855. begin
  2856. HexValue[0]:=HexDigitsW[((Ord(BinValue[i]) shr 4))];
  2857. HexValue[1]:=HexDigitsW[((Ord(BinValue[i]) and 15))];
  2858. Inc(HexValue,2);
  2859. end;
  2860. end;
  2861. procedure BinToHex(const BinBuffer: TBytes; BinBufOffset: Integer; var HexBuffer: TBytes; HexBufOffset: Integer; Count: Integer);
  2862. var
  2863. i : longint;
  2864. begin
  2865. for i:=0 to Count-1 do
  2866. begin
  2867. HexBuffer[HexBufOffset+2*i+0]:=Byte(HexDigits[(BinBuffer[BinBufOffset + i] shr 4)]);
  2868. HexBuffer[HexBufOffset+2*i+1]:=Byte(HexDigits[(BinBuffer[BinBufOffset + i] and 15)]);
  2869. end;
  2870. end;
  2871. procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer);
  2872. begin
  2873. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2874. end;
  2875. procedure BinToHex(BinValue: Pointer; HexValue: PWideChar; BinBufSize: Integer);
  2876. begin
  2877. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2878. end;
  2879. procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer);
  2880. begin
  2881. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2882. end;
  2883. procedure BinToHex(const BinValue; HexValue: PWideChar; BinBufSize: Integer);
  2884. begin
  2885. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2886. end;
  2887. function HexToBin(HexValue, BinValue: PAnsiChar; BinBufSize: Integer): Integer;
  2888. // more complex, have to accept more than bintohex
  2889. // A..F    1000001
  2890. // a..f    1100001
  2891. // 0..9     110000
  2892. var i,j,h,l : integer;
  2893. begin
  2894. i:=binbufsize;
  2895. while (i>0) do
  2896. begin
  2897. if hexvalue^ IN ['A'..'F','a'..'f'] then
  2898. h:=((ord(hexvalue^)+9) and 15)
  2899. else if hexvalue^ IN ['0'..'9'] then
  2900. h:=((ord(hexvalue^)) and 15)
  2901. else
  2902. break;
  2903. inc(hexvalue);
  2904. if hexvalue^ IN ['A'..'F','a'..'f'] then
  2905. l:=(ord(hexvalue^)+9) and 15
  2906. else if hexvalue^ IN ['0'..'9'] then
  2907. l:=(ord(hexvalue^)) and 15
  2908. else
  2909. break;
  2910. j := l + (h shl 4);
  2911. inc(hexvalue);
  2912. binvalue^:=chr(j);
  2913. inc(binvalue);
  2914. dec(i);
  2915. end;
  2916. result:=binbufsize-i;
  2917. end;
  2918. function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt;
  2919. var i,j:SizeInt;
  2920. begin
  2921. if PAnsiChar(pointer(s))=nil then
  2922. j:=0
  2923. else
  2924. begin
  2925. i:=length(s);
  2926. j:=count;
  2927. if j>i then
  2928. begin
  2929. result:=0;
  2930. exit;
  2931. end;
  2932. while (j<=i) and (not (s[j] in c)) do inc(j);
  2933. if (j>i) then
  2934. j:=0; // not found.
  2935. end;
  2936. result:=j;
  2937. end;
  2938. function PosSet(const c: TSysCharSet; const s: ansistring): SizeInt;
  2939. begin
  2940. result:=possetex(c,s,1);
  2941. end;
  2942. function PosSetEx(const c: string; const s: ansistring; count: Integer): SizeInt;
  2943. var cset : TSysCharSet;
  2944. i : SizeInt;
  2945. begin
  2946. cset:=[];
  2947. if length(c)>0 then
  2948. for i:=1 to length(c) do
  2949. include(cset,c[i]);
  2950. result:=possetex(cset,s,count);
  2951. end;
  2952. function PosSet(const c: string; const s: ansistring): SizeInt;
  2953. var cset : TSysCharSet;
  2954. i : SizeInt;
  2955. begin
  2956. cset:=[];
  2957. if length(c)>0 then
  2958. for i:=1 to length(c) do
  2959. include(cset,c[i]);
  2960. result:=possetex(cset,s,1);
  2961. end;
  2962. procedure Removeleadingchars(VAR S: AnsiString; const CSet: TSysCharset);
  2963. VAR I,J : Longint;
  2964. Begin
  2965. I:=Length(S);
  2966. IF (I>0) Then
  2967. Begin
  2968. J:=1;
  2969. While (J<=I) And (S[J] IN CSet) DO
  2970. INC(J);
  2971. IF J>1 Then
  2972. Delete(S,1,J-1);
  2973. End;
  2974. End;
  2975. procedure Removeleadingchars(VAR S: UnicodeString; const CSet: TSysCharset);
  2976. VAR I,J : Longint;
  2977. Begin
  2978. I:=Length(S);
  2979. IF (I>0) Then
  2980. Begin
  2981. J:=1;
  2982. While (J<=I) And (S[J] IN CSet) DO
  2983. INC(J);
  2984. IF J>1 Then
  2985. Delete(S,1,J-1);
  2986. End;
  2987. End;
  2988. function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
  2989. begin
  2990. result:=s;
  2991. removeleadingchars(result,cset);
  2992. end;
  2993. procedure RemoveTrailingChars(VAR S: AnsiString; const CSet: TSysCharset);
  2994. VAR I,J: LONGINT;
  2995. Begin
  2996. I:=Length(S);
  2997. IF (I>0) Then
  2998. Begin
  2999. J:=I;
  3000. While (j>0) and (S[J] IN CSet) DO DEC(J);
  3001. IF J<>I Then
  3002. SetLength(S,J);
  3003. End;
  3004. End;
  3005. procedure RemoveTrailingChars(VAR S: UnicodeString; const CSet: TSysCharset);
  3006. VAR I,J: LONGINT;
  3007. Begin
  3008. I:=Length(S);
  3009. IF (I>0) Then
  3010. Begin
  3011. J:=I;
  3012. While (j>0) and (S[J] IN CSet) DO DEC(J);
  3013. IF J<>I Then
  3014. SetLength(S,J);
  3015. End;
  3016. End;
  3017. function TrimRightSet(const S: String; const CSet: TSysCharSet): String;
  3018. begin
  3019. result:=s;
  3020. RemoveTrailingchars(result,cset);
  3021. end;
  3022. procedure RemovePadChars(VAR S: AnsiString; const CSet: TSysCharset);
  3023. VAR I,J,K: LONGINT;
  3024. Begin
  3025. I:=Length(S);
  3026. IF (I>0) Then
  3027. Begin
  3028. J:=I;
  3029. While (j>0) and (S[J] IN CSet) DO DEC(J);
  3030. if j=0 Then
  3031. begin
  3032. s:='';
  3033. exit;
  3034. end;
  3035. k:=1;
  3036. While (k<=I) And (S[k] IN CSet) DO
  3037. INC(k);
  3038. IF k>1 Then
  3039. begin
  3040. move(s[k],s[1],j-k+1);
  3041. setlength(s,j-k+1);
  3042. end
  3043. else
  3044. setlength(s,j);
  3045. End;
  3046. End;
  3047. procedure RemovePadChars(VAR S: UnicodeString; const CSet: TSysCharset);
  3048. VAR I,J,K: LONGINT;
  3049. Begin
  3050. I:=Length(S);
  3051. IF (I>0) Then
  3052. Begin
  3053. J:=I;
  3054. While (j>0) and (S[J] IN CSet) DO DEC(J);
  3055. if j=0 Then
  3056. begin
  3057. s:='';
  3058. exit;
  3059. end;
  3060. k:=1;
  3061. While (k<=I) And (S[k] IN CSet) DO
  3062. INC(k);
  3063. IF k>1 Then
  3064. begin
  3065. move(s[k],s[1],j-k+1);
  3066. setlength(s,j-k+1);
  3067. end
  3068. else
  3069. setlength(s,j);
  3070. End;
  3071. End;
  3072. function TrimSet(const S: String;const CSet:TSysCharSet): String;
  3073. begin
  3074. result:=s;
  3075. RemovePadChars(result,cset);
  3076. end;
  3077. Function SplitCommandLine(S : RawByteString) : TRawByteStringArray;
  3078. Function GetNextWord : RawByteString;
  3079. Const
  3080. WhiteSpace = [' ',#9,#10,#13];
  3081. Literals = ['"',''''];
  3082. Var
  3083. Wstart,wend : Integer;
  3084. InLiteral : Boolean;
  3085. LastLiteral : AnsiChar;
  3086. Procedure AppendToResult;
  3087. begin
  3088. Result:=Result+Copy(S,WStart,WEnd-WStart);
  3089. WStart:=Wend+1;
  3090. end;
  3091. begin
  3092. Result:='';
  3093. WStart:=1;
  3094. While (WStart<=Length(S)) and charinset(S[WStart],WhiteSpace) do
  3095. Inc(WStart);
  3096. WEnd:=WStart;
  3097. InLiteral:=False;
  3098. LastLiteral:=#0;
  3099. While (Wend<=Length(S)) and (Not charinset(S[Wend],WhiteSpace) or InLiteral) do
  3100. begin
  3101. if charinset(S[Wend],Literals) then
  3102. If InLiteral then
  3103. begin
  3104. InLiteral:=Not (S[Wend]=LastLiteral);
  3105. if not InLiteral then
  3106. AppendToResult;
  3107. end
  3108. else
  3109. begin
  3110. InLiteral:=True;
  3111. LastLiteral:=S[Wend];
  3112. AppendToResult;
  3113. end;
  3114. inc(wend);
  3115. end;
  3116. AppendToResult;
  3117. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  3118. inc(Wend);
  3119. Delete(S,1,WEnd-1);
  3120. end;
  3121. Var
  3122. W : RawByteString;
  3123. len : Integer;
  3124. begin
  3125. Len:=0;
  3126. Result:=Default(TRawByteStringArray);
  3127. SetLength(Result,(Length(S) div 2)+1);
  3128. While Length(S)>0 do
  3129. begin
  3130. W:=GetNextWord;
  3131. If (W<>'') then
  3132. begin
  3133. Result[Len]:=W;
  3134. Inc(Len);
  3135. end;
  3136. end;
  3137. SetLength(Result,Len);
  3138. end;
  3139. Function SplitCommandLine(S : UnicodeString) : TUnicodeStringArray;
  3140. Function GetNextWord : UnicodeString;
  3141. Const
  3142. WhiteSpace = [' ',#9,#10,#13];
  3143. Literals = ['"',''''];
  3144. Var
  3145. Wstart,wend : Integer;
  3146. InLiteral : Boolean;
  3147. LastLiteral : AnsiChar;
  3148. Procedure AppendToResult;
  3149. begin
  3150. Result:=Result+Copy(S,WStart,WEnd-WStart);
  3151. WStart:=Wend+1;
  3152. end;
  3153. begin
  3154. Result:='';
  3155. WStart:=1;
  3156. While (WStart<=Length(S)) and charinset(S[WStart],WhiteSpace) do
  3157. Inc(WStart);
  3158. WEnd:=WStart;
  3159. InLiteral:=False;
  3160. LastLiteral:=#0;
  3161. While (Wend<=Length(S)) and (Not charinset(S[Wend],WhiteSpace) or InLiteral) do
  3162. begin
  3163. if charinset(S[Wend],Literals) then
  3164. If InLiteral then
  3165. begin
  3166. InLiteral:=Not (S[Wend]=LastLiteral);
  3167. if not InLiteral then
  3168. AppendToResult;
  3169. end
  3170. else
  3171. begin
  3172. InLiteral:=True;
  3173. LastLiteral:=S[Wend];
  3174. AppendToResult;
  3175. end;
  3176. inc(wend);
  3177. end;
  3178. AppendToResult;
  3179. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  3180. inc(Wend);
  3181. Delete(S,1,WEnd-1);
  3182. end;
  3183. Var
  3184. W : UnicodeString;
  3185. len : Integer;
  3186. begin
  3187. Len:=0;
  3188. Result:=Default(TUnicodeStringArray);
  3189. SetLength(Result,(Length(S) div 2)+1);
  3190. While Length(S)>0 do
  3191. begin
  3192. W:=GetNextWord;
  3193. If (W<>'') then
  3194. begin
  3195. Result[Len]:=W;
  3196. Inc(Len);
  3197. end;
  3198. end;
  3199. SetLength(Result,Len);
  3200. end;
  3201. end.