strutils.pp 95 KB

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