strutils.pp 99 KB

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