strutils.pp 96 KB

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