strutils.pp 102 KB

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