strutils.pp 95 KB

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