strutils.pp 95 KB

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