123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537 |
- {
- Delphi/Kylix compatibility unit: String handling routines.
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2005 by the Free Pascal development team
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}
- {$h+}
- {$inline on}
- {$modeswitch advancedrecords}
- {$IFNDEF FPC_DOTTEDUNITS}
- unit StrUtils;
- {$ENDIF FPC_DOTTEDUNITS}
- interface
- {$IFDEF FPC_DOTTEDUNITS}
- uses
- System.SysUtils, System.Types;
- {$ELSE FPC_DOTTEDUNITS}
- uses
- SysUtils, Types;
- {$ENDIF FPC_DOTTEDUNITS}
- { ---------------------------------------------------------------------
- Case insensitive search/replace
- ---------------------------------------------------------------------}
- Function AnsiResemblesText(const AText, AOther: AnsiString): Boolean;
- Function AnsiContainsText(const AText, ASubText: AnsiString): Boolean;
- Function AnsiStartsText(const ASubText, AText: AnsiString): Boolean;
- Function AnsiEndsText(const ASubText, AText: AnsiString): Boolean;
- function AnsiEndsText(const ASubText, AText: UnicodeString): Boolean;
- Function AnsiReplaceText(const AText, AFromText, AToText: AnsiString): AnsiString;inline;
- Function AnsiMatchText(const AText: AnsiString; const AValues: array of AnsiString): Boolean;inline;
- Function AnsiIndexText(const AText: AnsiString; const AValues: array of AnsiString): Integer;
- Function StartsText(const ASubText, AText: string): Boolean; inline;
- Function EndsText(const ASubText, AText: string): Boolean; inline;
- function ResemblesText(const AText, AOther: string): Boolean; inline;
- function ContainsText(const AText, ASubText: string): Boolean; inline;
- function MatchText(const AText: Ansistring; const AValues: array of Ansistring): Boolean; inline;
- function IndexText(const AText: Ansistring; const AValues: array of Ansistring): Integer; inline;
- { ---------------------------------------------------------------------
- Case sensitive search/replace
- ---------------------------------------------------------------------}
- Function AnsiContainsStr(const AText, ASubText: AnsiString): Boolean;inline;
- function AnsiContainsStr(const AText, ASubText: Unicodestring): Boolean; inline;
- Function AnsiStartsStr(const ASubText, AText: AnsiString): Boolean;
- Function AnsiStartsStr(const ASubText, AText: UnicodeString): Boolean;
- Function AnsiEndsStr(const ASubText, AText: AnsiString): Boolean;
- Function AnsiEndsStr(const ASubText, AText: UnicodeString): Boolean;
- Function AnsiReplaceStr(const AText, AFromText, AToText: AnsiString): AnsiString;inline;
- Function AnsiMatchStr(const AText: AnsiString; const AValues: array of AnsiString): Boolean;inline;
- Function AnsiIndexStr(const AText: Ansistring; const AValues: array of Ansistring): Integer;
- Function StartsStr(const ASubText, AText: string): Boolean;
- Function EndsStr(const ASubText, AText: string): Boolean;
- Function MatchStr(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
- Function MatchText(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
- Function IndexStr(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
- Function IndexText(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
- Operator in (const AText: Ansistring; const AValues: array of Ansistring):Boolean;inline;
- Operator in (const AText: UnicodeString; const AValues: array of UnicodeString):Boolean;inline;
- function ContainsStr(const AText, ASubText: string): Boolean; inline;
- function MatchStr(const AText: Ansistring; const AValues: array of Ansistring): Boolean; inline;
- function IndexStr(const AText: Ansistring; const AValues: array of Ansistring): Integer; inline;
- { ---------------------------------------------------------------------
- Miscellaneous
- ---------------------------------------------------------------------}
- Function DupeString(const AText: string; ACount: Integer): string;
- Function ReverseString(const AText: string): string;
- Function AnsiReverseString(const AText: AnsiString): AnsiString;inline;
- Function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
- Function RandomFrom(const AValues: array of string): string; overload;
- Function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string = ''): string; overload;
- Function IfThen(AValue: Boolean; const ATrue: TStringDynArray; const AFalse: TStringDynArray = nil): TStringDynArray; overload;
- function NaturalCompareText (const S1 , S2 : string ): Integer ;
- function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: AnsiChar): Integer;
- function SplitString(const S, Delimiters: string): TRTLStringDynArray;
- { ---------------------------------------------------------------------
- VB emulations.
- ---------------------------------------------------------------------}
- Function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
- Function RightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
- Function MidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;inline;
- Function RightBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;inline;
- Function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: SizeInt): AnsiString;inline;
- Function AnsiLeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
- Function AnsiRightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
- Function AnsiMidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;inline;
- Function LeftBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;inline;
- Function LeftStr(const AText: WideString; const ACount: SizeInt): WideString;inline;
- Function RightStr(const AText: WideString; const ACount: SizeInt): WideString;
- Function MidStr(const AText: WideString; const AStart, ACount: SizeInt): WideString;inline;
- { ---------------------------------------------------------------------
- Extended search and replace
- ---------------------------------------------------------------------}
- const
- { Default word delimiters are any character except the core alphanumerics. }
- WordDelimiters: set of AnsiChar = [#0..#255] - ['a'..'z','A'..'Z','1'..'9','0'];
-
- resourcestring
- SErrAmountStrings = 'Amount of search and replace strings don''t match';
- type
- TStringSearchOption = (soDown, soMatchCase, soWholeWord);
- TStringSearchOptions = set of TStringSearchOption;
- TStringSeachOption = TStringSearchOption;
- Function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String; Options: TStringSearchOptions): PAnsiChar;
- Function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String): PAnsiChar;inline; // ; Options: TStringSearchOptions = [soDown]
- Function PosEx(const SubStr, S: Ansistring; Offset: SizeInt): SizeInt;inline;
- Function PosEx(const SubStr, S: Ansistring): SizeInt;inline;
- Function PosEx(c:AnsiChar; const S: AnsiString; Offset: SizeInt): SizeInt;inline;
- Function PosEx(const SubStr, S: UnicodeString; Offset: SizeInt): SizeInt;inline;
- Function PosEx(c: WideChar; const S: UnicodeString; Offset: SizeInt): SizeInt;inline;
- Function PosEx(const SubStr, S: UnicodeString): Sizeint;inline;
- function StringsReplace(const S: Ansistring; OldPattern, NewPattern: array of Ansistring; Flags: TReplaceFlags): string;
- { ---------------------------------------------------------------------
- Delphi compat
- ---------------------------------------------------------------------}
- Function ReplaceStr(const AText, AFromText, AToText: string): string;inline;
- Function ReplaceText(const AText, AFromText, AToText: string): string;inline;
- { ---------------------------------------------------------------------
- Soundex Functions.
- ---------------------------------------------------------------------}
- type
- TSoundexLength = 1..MaxInt;
- Function Soundex(const AText: string; ALength: TSoundexLength): string;
- Function Soundex(const AText: string): string;inline; // ; ALength: TSoundexLength = 4
- type
- TSoundexIntLength = 1..8;
- Function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
- Function SoundexInt(const AText: string): Integer;inline; //; ALength: TSoundexIntLength = 4
- Function DecodeSoundexInt(AValue: Integer): string;
- Function SoundexWord(const AText: string): Word;
- Function DecodeSoundexWord(AValue: Word): string;
- Function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;inline;
- Function SoundexSimilar(const AText, AOther: string): Boolean;inline; //; ALength: TSoundexLength = 4
- Function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;inline;
- Function SoundexCompare(const AText, AOther: string): Integer;inline; //; ALength: TSoundexLength = 4
- Function SoundexProc(const AText, AOther: string): Boolean;
- type
- TCompareTextProc = Function(const AText, AOther: string): Boolean;
- Const
- AnsiResemblesProc: TCompareTextProc = @SoundexProc;
- ResemblesProc: TCompareTextProc = @SoundexProc;
- { ---------------------------------------------------------------------
- Other functions, based on RxStrUtils.
- ---------------------------------------------------------------------}
- type
- TRomanConversionStrictness = (rcsStrict, rcsRelaxed, rcsDontCare);
- resourcestring
- SInvalidRomanNumeral = '%s is not a valid Roman numeral';
- function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
- function DelSpace(const S: string): string;
- function DelChars(const S: string; Chr: Char): string;
- function DelChars(const S: string; Chars: TSysCharSet): string;
- function DelSpace1(const S: string): string;
- function Tab2Space(const S: string; Numb: Byte): string;
- function NPos(const C: string; const S: string; N: Integer): SizeInt;
- Function RPosEx(C:AnsiChar;const S : AnsiString;offs:SizeInt):SizeInt; overload;
- Function RPosEx(C:Unicodechar;const S : UnicodeString;offs:SizeInt):SizeInt; overload;
- Function RPosEx(Const Substr : AnsiString; Const Source : AnsiString;offs:SizeInt) : SizeInt; overload;
- Function RPosEx(Const Substr : UnicodeString; Const Source : UnicodeString;offs:SizeInt) : SizeInt; overload;
- Function RPos(c:AnsiChar;const S : AnsiString):SizeInt; overload; inline;
- Function RPos(c:Unicodechar;const S : UnicodeString):SizeInt; overload; inline;
- Function RPos(Const Substr : AnsiString; Const Source : AnsiString) : SizeInt; overload; inline;
- Function RPos(Const Substr : UnicodeString; Const Source : UnicodeString) : SizeInt; overload; inline;
- function AddChar(C: AnsiChar; const S: string; N: Integer): string;
- function AddCharR(C: AnsiChar; const S: string; N: Integer): string;
- function PadLeft(const S: string; N: Integer): string;inline;
- function PadRight(const S: string; N: Integer): string;inline;
- function PadCenter(const S: string; Len: SizeInt): string;
- function Copy2Symb(const S: string; Symb: AnsiChar): string;
- function Copy2SymbDel(var S: string; Symb: AnsiChar): string;
- function Copy2Space(const S: string): string;inline;
- function Copy2SpaceDel(var S: string): string;inline;
- function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
- function WordCount(const S: string; const WordDelims: TSysCharSet): SizeInt;
- function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): SizeInt;
- function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
- {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
- function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: SizeInt): string;
- {$ENDIF}
- function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: Integer): string;
- function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
- {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
- function ExtractSubstr(const S: string; var Pos: SizeInt; const Delims: TSysCharSet): string;
- {$ENDIF}
- function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
- function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
- function FindPart(const HelpWilds, InputStr: string): SizeInt;
- function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
- function XorString(const Key, Src: ShortString): ShortString;
- function XorEncode(const Key, Source: Ansistring): Ansistring;
- function XorDecode(const Key, Source: Ansistring): Ansistring;
- function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
- function Numb2USA(const S: string): string;
- function Hex2Dec(const S: string): Longint;
- function Hex2Dec64(const S: string): int64;
- function Dec2Numb(N: Longint; Len, Base: Byte): string;
- function Numb2Dec(S: string; Base: Byte): Longint;
- function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
- function IntToBin(Value: Longint; Digits: Integer): string;
- function IntToBin(Value: int64; Digits:integer): string;
- function IntToRoman(Value: Longint): string;
- function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
- function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
- function RomanToIntDef(Const S : String; const ADefault: Longint = 0; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
- procedure BinToHex(const BinBuffer: TBytes; BinBufOffset: Integer; var HexBuffer: TBytes; HexBufOffset: Integer; Count: Integer); overload;
- procedure BinToHex(BinValue: Pointer; HexValue: PWideChar; BinBufSize: Integer); overload;
- procedure BinToHex(const BinValue; HexValue: PWideChar; BinBufSize: Integer); overload;
- procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer); overload;
- procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer); overload;
- procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer); overload;
- procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer); overload;
- function HexToBin(HexText: PAnsiChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer; overload;
- function HexToBin(const HexText: PWideChar; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer; overload;
- function HexToBin(const HexText: TBytes; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer; overload;
- function HexToBin(HexText: PWideChar; BinBuffer: Pointer; BinBufSize: Integer): Integer; overload;
- function HexToBin(const HexText: PWideChar; var BinBuffer; BinBufSize: Integer): Integer; overload;
- function HexToBin(HexText: PWideChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer; overload;
- function HexToBin(HexText: PAnsiChar; var BinBuffer; BinBufSize: Integer): Integer; overload;
- function HexToBin(const HexText: PAnsiChar; BinBuffer: Pointer; BinBufSize: Integer): Integer; overload;
- const
- DigitChars = ['0'..'9'];
- Brackets = ['(',')','[',']','{','}'];
- StdWordDelims = [#0..' ',',','.',';','/','\',':','''','"','`'] + Brackets;
- StdSwitchChars = ['-','/'];
- function PosSet (const c:TSysCharSet;const s : ansistring ):SizeInt;
- function PosSet (const c:string;const s : ansistring ):SizeInt;
- function PosSetEx (const c:TSysCharSet;const s : ansistring;count:Integer ):SizeInt;
- function PosSetEx (const c:string;const s : ansistring;count:Integer ):SizeInt;
- Procedure RemoveLeadingChars(VAR S : AnsiString; Const CSet:TSysCharset);
- Procedure RemoveTrailingChars(VAR S : AnsiString;Const CSet:TSysCharset);
- Procedure RemoveLeadingChars(VAR S : UnicodeString; Const CSet:TSysCharset);
- Procedure RemoveTrailingChars(VAR S : UnicodeString;Const CSet:TSysCharset);
- Procedure RemovePadChars(VAR S : AnsiString;Const CSet:TSysCharset);
- procedure RemovePadChars(VAR S: UnicodeString; const CSet: TSysCharset);
- function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
- Function TrimRightSet(const S: String;const CSet:TSysCharSet): String;
- function TrimSet(const S: String;const CSet:TSysCharSet): String;
- type
- SizeIntArray = array of SizeInt;
- Function FindMatchesBoyerMooreCaseSensitive(const S,OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
- Function FindMatchesBoyerMooreCaseSensitive(const S,OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
- Function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
- Function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
- Type
- TStringReplaceAlgorithm = (sraDefault, // Default algoritm as used in StringUtils.
- sraManySmall, // Algorithm optimized for many small replacements.
- sraBoyerMoore // Algorithm optimized for long replacements.
- );
- Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
- Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
- { We need these for backwards compatibility:
- The compiler will stop searching and convert to ansistring if the widestring version of stringreplace is used.
- They currently simply refer to sysutils, till the new mechanisms are proven to work with unicode.}
- {$IF SIZEOF(CHAR)=1}
- Function StringReplace(const S, OldPattern, NewPattern: unicodestring; Flags: TReplaceFlags): unicodestring; overload;
- Function StringReplace(const S, OldPattern, NewPattern: widestring; Flags: TReplaceFlags): widestring; overload;
- {$ENDIF}
- Type
- TRawByteStringArray = Array of RawByteString;
- TUnicodeStringArray = Array of UnicodeString;
- Function SplitCommandLine(S : RawByteString) : TRawByteStringArray;
- Function SplitCommandLine(S : UnicodeString) : TUnicodeStringArray;
- implementation
- {$IFDEF FPC_DOTTEDUNITS}
- uses System.SysConst; // HexDigits
- {$ELSE FPC_DOTTEDUNITS}
- uses sysconst; // HexDigits
- {$ENDIF FPC_DOTTEDUNITS}
- type
- // Shared between case-sensitive and case-insensitive versions.
- BoyerMoore = record
- DeltaJumpTable1: array[AnsiChar] of SizeInt;
- DeltaJumpTable2: SizeIntArray;
- MatchesCount: SizeInt; //Stores the amount of replaces that will take place
- MatchesAllocatedLimit: SizeInt; //Currently allocated space for matches.
- Matches: ^SizeIntArray;
- class var
- LCaseArray: array[AnsiChar] of AnsiChar; //Array of lowercased alphabet
- LCaseArrayPrepared: boolean;
- procedure Init(var aMatches: SizeIntArray); inline;
- procedure MakeDeltaJumpTables(aPattern: PAnsiChar; aPatternSize: SizeInt);
- procedure AddMatch(aPosition: SizeInt);
- class function Max(a, b: SizeInt): SizeInt; static; inline;
- class procedure IncrementEverything(var aMatches: array of SizeInt); static; // Make positions 1-based.
- class procedure PrepareLCaseArray; static;
- end;
- procedure BoyerMoore.Init(var aMatches: SizeIntArray);
- begin
- MatchesCount:=0;
- MatchesAllocatedLimit:=0;
- Matches:=@aMatches;
- end;
- procedure BoyerMoore.MakeDeltaJumpTables(aPattern: PAnsiChar; aPatternSize: SizeInt);
- var
- i, Position, LastPrefixIndex, SuffixLength: SizeInt;
- begin
- {$if sizeof(SizeInt)=sizeof(word)} FillWord
- {$elseif sizeof(SizeInt)=sizeof(dword)} FillDWord
- {$elseif sizeof(SizeInt)=sizeof(qword)} FillQWord
- {$else} {$error unknown SizeInt size}
- {$endif}
- (DeltaJumpTable1, Length(DeltaJumpTable1), SizeUint(aPatternSize));
- //Last AnsiChar do not enter in the equation
- for i := 0 to aPatternSize - 1 - 1 do
- DeltaJumpTable1[aPattern[i]]:=aPatternSize -1 - i;
- SetLength(DeltaJumpTable2, aPatternSize);
- LastPrefixIndex:=aPatternSize-1;
- Position:=aPatternSize-1;
- while Position>=0 do begin
- if CompareByte(aPattern^, aPattern[Position+1], (aPatternSize-Position-1)*SizeOf(aPattern[0]))=0 then
- LastPrefixIndex := Position+1;
- DeltaJumpTable2[Position] := LastPrefixIndex + (aPatternSize-1 - Position);
- Dec(Position);
- end;
- Position:=0;
- while Position<aPatternSize-1 do begin
- SuffixLength:=0;
- while (SuffixLength<Position) and (aPattern[Position-SuffixLength] = aPattern[aPatternSize-1-SuffixLength]) do
- inc(SuffixLength);
- if aPattern[Position-SuffixLength] <> aPattern[aPatternSize-1-SuffixLength] then
- DeltaJumpTable2[aPatternSize - 1 - SuffixLength] := aPatternSize - 1 - Position + SuffixLength;
- Inc(Position);
- end;
- end;
- procedure BoyerMoore.AddMatch(aPosition: SizeInt);
- begin
- if MatchesCount=MatchesAllocatedLimit then begin
- MatchesAllocatedLimit:=MatchesAllocatedLimit+4+SizeInt(SizeUint(MatchesAllocatedLimit) div 4+SizeUint(MatchesAllocatedLimit) div 8); // const + 37.5%
- SetLength(Matches^,MatchesAllocatedLimit);
- end;
- Matches^[MatchesCount]:=aPosition;
- inc(MatchesCount);
- end;
- class function BoyerMoore.Max(a, b: SizeInt): SizeInt;
- begin
- if a>b then Result:=a else Result:=b;
- end;
- class procedure BoyerMoore.IncrementEverything(var aMatches: array of SizeInt); static;
- var
- i: SizeInt;
- begin
- for i:=0 to High(aMatches) do
- Inc(aMatches[i]);
- end;
- class procedure BoyerMoore.PrepareLCaseArray;
- var
- c: AnsiChar;
- begin
- for c in AnsiChar do
- LCaseArray[c]:=AnsiLowerCase(c)[1];
- WriteBarrier; // Write LCaseArrayPrepared only after LCaseArray contents.
- LCaseArrayPrepared:=true;
- end;
- (*
- FindMatchesBoyerMooreCaseSensitive
- Finds one or many ocurrences of an ansistring in another ansistring.
- It is case sensitive.
- * Parameters:
- S: The PAnsiChar to be searched in. (Read only).
- OldPattern: The PAnsiChar to be searched. (Read only).
- SSize: The size of S in Chars. (Read only).
- OldPatternSize: The size of OldPatter in chars. (Read only).
- aMatches: SizeInt array where match indexes are returned (zero based) (write only).
- aMatchAll: Finds all matches, not just the first one. (Read only).
- * Returns:
- True if at least one occurence was found.
- The function is based in the Boyer-Moore algorithm.
- *)
- function FindMatchesBoyerMooreCaseSensitive(const S, OldPattern: PAnsiChar;
- const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray;
- const aMatchAll: Boolean) : Boolean;
- var
- i,j: SizeInt;
- bm: BoyerMoore;
- begin
- aMatches:=nil;
- if OldPatternSize=0 then
- Exit(False);
- bm.Init(aMatches);
- bm.MakeDeltaJumpTables(OldPattern,OldPatternSize);
- i:=OldPatternSize-1;
- while i < SSize do begin
- j:=OldPatternSize-1;
- while (j>=0) and (S[i] = OldPattern[j]) do begin
- dec(i);
- dec(j);
- end;
- if (j<0) then begin
- bm.AddMatch(i+1);
- //Only first match ?
- if not aMatchAll then break;
- inc(i,bm.DeltaJumpTable2[0]+1);
- end else
- i:=i + bm.Max(bm.DeltaJumpTable1[s[i]],bm.DeltaJumpTable2[j]);
- end;
- SetLength(aMatches,bm.MatchesCount);
- Result:=bm.MatchesCount>0;
- end;
- function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out
- aMatches: SizeIntArray; const aMatchAll: Boolean): Boolean;
- var
- i,j: SizeInt;
- lPattern: PAnsiChar; //Lowercased OldPattern
- bm: BoyerMoore;
- lPatternStore: ansistring;
- begin
- aMatches:=nil;
- if OldPatternSize=0 then
- Exit(False);
- //Build an internal array of lowercase version of every possible AnsiChar.
- if not bm.LCaseArrayPrepared then
- bm.PrepareLCaseArray;
- ReadBarrier; // Read LCaseArray contents only after LCaseArrayPrepared.
- //Create the new lowercased pattern. Or avoid and reuse OldPattern if nothing to lowercase!
- lPattern:=OldPattern;
- for i := 0 to OldPatternSize-1 do
- if bm.LCaseArray[OldPattern[i]]<>OldPattern[i] then begin
- SetLength(lPatternStore,OldPatternSize);
- lPattern:=PAnsiChar(Pointer(lPatternStore));
- Move(OldPattern^,lPattern^,i*sizeof(AnsiChar));
- for j := i to OldPatternSize-1 do
- lPattern[j]:=bm.LCaseArray[OldPattern[j]];
- break;
- end;
- bm.Init(aMatches);
- bm.MakeDeltaJumpTables(lPattern,OldPatternSize);
- i:=OldPatternSize-1;
- while i < SSize do begin
- j:=OldPatternSize-1;
- while (j>=0) and (bm.LCaseArray[S[i]] = lPattern[j]) do begin
- dec(i);
- dec(j);
- end;
- if (j<0) then begin
- bm.AddMatch(i+1);
- //Only first match ?
- if not aMatchAll then break;
- inc(i,bm.DeltaJumpTable2[0]+1);
- end else
- i:=i + bm.Max(bm.DeltaJumpTable1[bm.LCaseArray[s[i]]],bm.DeltaJumpTable2[j]);
- end;
- SetLength(aMatches,bm.MatchesCount);
- Result:=bm.MatchesCount>0;
- end;
- function StringReplaceFast(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer): string;
- const
- MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
- var
- //Stores where a replace will take place
- Matches: array of SizeInt;
- //Stores the amount of replaces that will take place
- MatchesCount: SizeInt;
- //Currently allocated space for matches.
- MatchesAllocatedLimit: SizeInt;
- //Uppercase version of pattern
- PatternUppercase: string;
- //Lowercase version of pattern
- PatternLowerCase: string;
- //Index
- MatchIndex: SizeInt;
- MatchLimit: SizeInt;
- MatchInternal: SizeInt;
- MatchTarget: SizeInt;
- AdvanceIndex: SizeInt;
- //Miscelanous variables
- OldPatternSize: SizeInt;
- NewPatternSize: SizeInt;
- //Resizes the allocated space for replacement index
- procedure ResizeAllocatedMatches;
- begin
- MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
- SetLength(Matches,MatchesAllocatedLimit);
- end;
- //Add a match to be replaced
- procedure AddMatch(const aPosition: SizeInt); inline;
- begin
- if MatchesCount = MatchesAllocatedLimit then begin
- ResizeAllocatedMatches;
- end;
- Matches[MatchesCount]:=aPosition;
- inc(MatchesCount);
- end;
- begin
- aCount:=0;
- if (OldPattern='') or (Length(OldPattern)>Length(S)) then begin
- //This cases will never match nothing.
- Result:=S;
- exit;
- end;
- Result:='';
- OldPatternSize:=Length(OldPattern);
- MatchesCount:=0;
- MatchesAllocatedLimit:=0;
- if rfIgnoreCase in Flags then begin
- //Different algorithm for case sensitive and insensitive
- //This is insensitive, so 2 new ansistrings are created for search pattern, one upper and one lower case.
- //It is easy, usually, to create 2 versions of the match pattern than uppercased and lowered case each
- //character in the "to be matched" string.
- PatternUppercase:=AnsiUpperCase(OldPattern);
- PatternLowerCase:=AnsiLowerCase(OldPattern);
- MatchIndex:=Length(OldPattern);
- MatchLimit:=Length(S);
- NewPatternSize:=Length(NewPattern);
- while MatchIndex <= MatchLimit do begin
- if (S[MatchIndex]=PatternLowerCase[OldPatternSize]) or (S[MatchIndex]=PatternUppercase[OldPatternSize]) then begin
- //Match backwards...
- MatchInternal:=OldPatternSize-1;
- MatchTarget:=MatchIndex-1;
- while MatchInternal>=1 do begin
- if (S[MatchTarget]=PatternLowerCase[MatchInternal]) or (S[MatchTarget]=PatternUppercase[MatchInternal]) then begin
- dec(MatchInternal);
- dec(MatchTarget);
- end else begin
- break;
- end;
- end;
- if MatchInternal=0 then begin
- //Match found, all AnsiChar meet the sequence
- //MatchTarget points to AnsiChar before, so matching is +1
- AddMatch(MatchTarget+1);
- inc(MatchIndex,OldPatternSize);
- if not (rfReplaceAll in Flags) then begin
- break;
- end;
- end else begin
- //Match not found
- inc(MatchIndex);
- end;
- end else begin
- inc(MatchIndex);
- end;
- end;
- end else begin
- //Different algorithm for case sensitive and insensitive
- //This is sensitive, so just 1 binary comprare
- MatchIndex:=Length(OldPattern);
- MatchLimit:=Length(S);
- NewPatternSize:=Length(NewPattern);
- while MatchIndex <= MatchLimit do begin
- if (S[MatchIndex]=OldPattern[OldPatternSize]) then begin
- //Match backwards...
- MatchInternal:=OldPatternSize-1;
- MatchTarget:=MatchIndex-1;
- while MatchInternal>=1 do begin
- if (S[MatchTarget]=OldPattern[MatchInternal]) then begin
- dec(MatchInternal);
- dec(MatchTarget);
- end else begin
- break;
- end;
- end;
- if MatchInternal=0 then begin
- //Match found, all AnsiChar meet the sequence
- //MatchTarget points to AnsiChar before, so matching is +1
- AddMatch(MatchTarget+1);
- inc(MatchIndex,OldPatternSize);
- if not (rfReplaceAll in Flags) then begin
- break;
- end;
- end else begin
- //Match not found
- inc(MatchIndex);
- end;
- end else begin
- inc(MatchIndex);
- end;
- end;
- end;
- //Create room enough for the result string
- aCount:=MatchesCount;
- SetLength(Result,Length(S)-OldPatternSize*MatchesCount+NewPatternSize*MatchesCount);
- MatchIndex:=1;
- MatchTarget:=1;
- //Matches[x] are 1 based offsets
- for MatchInternal := 0 to Pred(MatchesCount) do begin
- //Copy information up to next match
- AdvanceIndex:=Matches[MatchInternal]-MatchIndex;
- if AdvanceIndex>0 then begin
- move(S[MatchIndex],Result[MatchTarget],AdvanceIndex);
- inc(MatchTarget,AdvanceIndex);
- inc(MatchIndex,AdvanceIndex);
- end;
- //Copy the new replace information string
- if NewPatternSize>0 then begin
- move(NewPattern[1],Result[MatchTarget],NewPatternSize);
- inc(MatchTarget,NewPatternSize);
- end;
- inc(MatchIndex,OldPatternSize);
- end;
- if MatchTarget<=Length(Result) then begin
- //Add remain data at the end of source.
- move(S[MatchIndex],Result[MatchTarget],Length(Result)-MatchTarget+1);
- end;
- end;
- (*
- StringReplaceBoyerMoore
- Replaces one or many ocurrences of an ansistring in another ansistring by a new one.
- It can perform the compare ignoring case (ansi).
- * Parameters (Read only):
- S: The string to be searched in.
- OldPattern: The string to be searched.
- NewPattern: The string to replace OldPattern matches.
- Flags:
- rfReplaceAll: Replace all occurrences.
- rfIgnoreCase: Ignore case in OldPattern matching.
- * Returns:
- The modified string (if needed).
- It is memory conservative, just sizeof(SizeInt) per match in blocks off 100 matches
- plus Length(OldPattern)*2 in the case of ignoring case.
- Memory copies are the minimun necessary.
- Algorithm based in the Boyer-Moore string search algorithm.
- It is faster when the "S" string is very long and the OldPattern is also
- very big. As much big the OldPattern is, faster the search is too.
- It uses 2 different helper versions of Boyer-Moore algorithm, one for case
- sensitive and one for case INsensitive for speed reasons.
- *)
- function StringReplaceBoyerMoore(const S, OldPattern, NewPattern: string;Flags: TReplaceFlags; out aCount : Integer): string;
- var
- Matches: SizeIntArray;
- OldPatternSize: SizeInt;
- NewPatternSize: SizeInt;
- MatchesCount: SizeInt;
- MatchIndex: SizeInt;
- MatchTarget: SizeInt;
- MatchInternal: SizeInt;
- AdvanceIndex: SizeInt;
- begin
- aCount:=0;
- OldPatternSize:=Length(OldPattern);
- NewPatternSize:=Length(NewPattern);
- if (OldPattern='') or (Length(OldPattern)>Length(S)) then begin
- Result:=S;
- exit;
- end;
- if rfIgnoreCase in Flags then begin
- FindMatchesBoyerMooreCaseINSensitive(@s[1],@OldPattern[1],Length(S),Length(OldPattern),Matches, rfReplaceAll in Flags);
- end else begin
- FindMatchesBoyerMooreCaseSensitive(@s[1],@OldPattern[1],Length(S),Length(OldPattern),Matches, rfReplaceAll in Flags);
- end;
- MatchesCount:=Length(Matches);
- aCount:=MatchesCount;
- //Create room enougth for the result string
- SetLength(Result,Length(S)-OldPatternSize*MatchesCount+NewPatternSize*MatchesCount);
- MatchIndex:=1;
- MatchTarget:=1;
- //Matches[x] are 0 based offsets
- for MatchInternal := 0 to Pred(MatchesCount) do begin
- //Copy information up to next match
- AdvanceIndex:=Matches[MatchInternal]+1-MatchIndex;
- if AdvanceIndex>0 then begin
- move(S[MatchIndex],Result[MatchTarget],AdvanceIndex);
- inc(MatchTarget,AdvanceIndex);
- inc(MatchIndex,AdvanceIndex);
- end;
- //Copy the new replace information string
- if NewPatternSize>0 then begin
- move(NewPattern[1],Result[MatchTarget],NewPatternSize);
- inc(MatchTarget,NewPatternSize);
- end;
- inc(MatchIndex,OldPatternSize);
- end;
- if MatchTarget<=Length(Result) then begin
- //Add remain data at the end of source.
- move(S[MatchIndex],Result[MatchTarget],Length(Result)-MatchTarget+1);
- end;
- end;
- function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; Algorithm: TStringReplaceAlgorithm): string;
- Var
- C : Integer;
- begin
- Result:=StringReplace(S, OldPattern, NewPattern, Flags,C,Algorithm);
- end;
- Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
- begin
- Case Algorithm of
- sraDefault : Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.StringReplace(S,OldPattern,NewPattern,Flags,aCount);
- sraManySmall : Result:=StringReplaceFast(S,OldPattern,NewPattern,Flags,aCount);
- sraBoyerMoore : Result:=StringReplaceBoyerMoore(S,OldPattern,NewPattern,Flags,aCount);
- end;
- end;
- {$IF SIZEOF(CHAR)=1}
- function StringReplace(const S, OldPattern, NewPattern: unicodestring; Flags: TReplaceFlags): unicodestring;
- begin
- Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.StringReplace(S,OldPattern,NewPattern,Flags);
- end;
- function StringReplace(const S, OldPattern, NewPattern: widestring; Flags: TReplaceFlags): widestring;
- begin
- Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.StringReplace(S,OldPattern,NewPattern,Flags);
- end;
- {$ENDIF}
- function FindMatchesBoyerMooreCaseSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean
- ): Boolean;
- begin
- Result:=FindMatchesBoyerMooreCaseSensitive(PAnsiChar(S),PAnsiChar(OldPattern),Length(S),Length(OldPattern),aMatches,aMatchAll);
- BoyerMoore.IncrementEverything(AMatches);
- end;
- function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean
- ): Boolean;
- begin
- Result:=FindMatchesBoyerMooreCaseInSensitive(PAnsiChar(S),PAnsiChar(OldPattern),Length(S),Length(OldPattern),aMatches,aMatchAll);
- BoyerMoore.IncrementEverything(AMatches);
- end;
- { ---------------------------------------------------------------------
- Possibly Exception raising functions
- ---------------------------------------------------------------------}
- function Hex2Dec(const S: string): Longint;
- var
- HexStr: string;
- begin
- if Pos('$',S)=0 then
- HexStr:='$'+ S
- else
- HexStr:=S;
- Result:=StrToInt(HexStr);
- end;
- function Hex2Dec64(const S: string): int64;
- var
- HexStr: string;
- begin
- if Pos('$',S)=0 then
- HexStr:='$'+ S
- else
- HexStr:=S;
- Result:=StrToInt64(HexStr);
- end;
- {
- We turn off implicit exceptions, since these routines are tested, and it
- saves 20% codesize (and some speed) and don't throw exceptions, except maybe
- heap related. If they don't, that is consider a bug.
- In the future, be wary with routines that use strtoint, floating point
- and/or format() derivatives. And check every divisor for 0.
- }
- {$IMPLICITEXCEPTIONS OFF}
- { ---------------------------------------------------------------------
- Case insensitive search/replace
- ---------------------------------------------------------------------}
- function AnsiResemblesText(const AText, AOther: AnsiString): Boolean;
- begin
- if Assigned(AnsiResemblesProc) then
- Result:=AnsiResemblesProc(AText,AOther)
- else
- Result:=False;
- end;
- function AnsiContainsText(const AText, ASubText: AnsiString): Boolean;
- begin
- AnsiContainsText:=AnsiPos(AnsiUppercase(ASubText),AnsiUppercase(AText))>0;
- end;
- function AnsiStartsText(const ASubText, AText: AnsiString): Boolean;
- begin
- Result := (ASubText = '') or AnsiSameText(LeftStr(AText, Length(ASubText)), ASubText);
- end;
- function AnsiEndsText(const ASubText, AText: AnsiString): Boolean;
- begin
- Result := (ASubText = '') or AnsiSameText(RightStr(AText, Length(ASubText)), ASubText);
- end;
- function AnsiEndsText(const ASubText, AText: UnicodeString): Boolean;
- begin
- Result := (ASubText = '') or SameText(RightStr(AText, Length(ASubText)), ASubText);
- end;
- function StartsText(const ASubText, AText: String): Boolean; inline;
- begin
- Result := AnsiStartsText(ASubText, AText);
- end;
- function EndsText(const ASubText, AText: string): Boolean;
- begin
- Result := AnsiEndsText(ASubText, AText);
- end;
- function ResemblesText(const AText, AOther: string): Boolean;
- begin
- if Assigned(ResemblesProc) then
- Result := ResemblesProc(AText, AOther)
- else
- Result := False;
- end;
- function ContainsText(const AText, ASubText: string): Boolean;
- begin
- Result := AnsiContainsText(AText, ASubText);
- end;
- function MatchText(const AText: Ansistring; const AValues: array of Ansistring): Boolean;
- begin
- Result := AnsiMatchText(AText, AValues);
- end;
- function IndexText(const AText: Ansistring; const AValues: array of Ansistring): Integer;
- begin
- Result := AnsiIndexText(AText, AValues);
- end;
- function ContainsStr(const AText, ASubText: String): Boolean;
- begin
- Result := AnsiContainsStr(AText, ASubText);
- end;
- function MatchStr(const AText: Ansistring; const AValues: array of Ansistring): Boolean;
- begin
- Result := AnsiMatchStr(AText, AValues);
- end;
- function IndexStr(const AText: AnsiString; const AValues: array of AnsiString): Integer;
- begin
- Result := AnsiIndexStr(AText, AValues);
- end;
- function AnsiReplaceText(const AText, AFromText, AToText: Ansistring): Ansistring;
- begin
- Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll,rfIgnoreCase]);
- end;
- function AnsiMatchText(const AText: Ansistring; const AValues: array of AnsiString): Boolean;
- begin
- Result:=(AnsiIndexText(AText,AValues)<>-1)
- end;
- function AnsiIndexText(const AText: AnsiString; const AValues: array of Ansistring): Integer;
- begin
- for Result := Low(AValues) to High(AValues) do
- if AnsiSameText(AValues[Result], AText) then
- Exit;
- Result := -1;
- end;
- { ---------------------------------------------------------------------
- Case sensitive search/replace
- ---------------------------------------------------------------------}
- function AnsiContainsStr(const AText, ASubText: Ansistring): Boolean;
- begin
- Result := AnsiPos(ASubText,AText)>0;
- end;
- function AnsiContainsStr(const AText, ASubText: Unicodestring): Boolean;
- begin
- Result := AnsiPos(ASubText,AText)>0;
- end;
- function AnsiStartsStr(const ASubText, AText: AnsiString): Boolean;
- begin
- Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText);
- end;
- function AnsiStartsStr(const ASubText, AText: UnicodeString): Boolean;
- begin
- Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText);
- end;
- function AnsiEndsStr(const ASubText, AText: AnsiString): Boolean;
- begin
- Result := (ASubText = '') or (RightStr(AText, Length(ASubText)) = ASubText);
- end;
- function AnsiEndsStr(const ASubText, AText: UnicodeString): Boolean;
- begin
- Result := (ASubText = '') or (RightStr(AText, Length(ASubText)) = ASubText);
- end;
- function StartsStr(const ASubText, AText: string): Boolean;
- begin
- if (Length(AText) >= Length(ASubText)) and (ASubText <> '') then
- Result := StrLComp(PChar(ASubText), PChar(AText), Length(ASubText)) = 0
- else
- Result := (AsubText='');
- end;
- function EndsStr(const ASubText, AText: string): Boolean;
- begin
- if Length(AText) >= Length(ASubText) then
- Result := StrLComp(PChar(ASubText),
- PChar(AText) + Length(AText) - Length(ASubText), Length(ASubText)) = 0
- else
- Result := False;
- end;
- function AnsiReplaceStr(const AText, AFromText, AToText: AnsiString): AnsiString;
- begin
- Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll]);
- end;
- function AnsiMatchStr(const AText: AnsiString; const AValues: array of AnsiString): Boolean;
- begin
- Result:=AnsiIndexStr(AText,Avalues)<>-1;
- end;
- function AnsiIndexStr(const AText: AnsiString; const AValues: array of AnsiString): Integer;
- begin
- for result:=low(AValues) to High(Avalues) do
- if (avalues[result]=AText) Then
- exit; // make sure it is the first val.
- result:=-1;
- end;
- function MatchStr(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
- begin
- Result := IndexStr(AText,AValues) <> -1;
- end;
- function MatchText(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
- begin
- Result := IndexText(AText,AValues) <> -1;
- end;
- function IndexStr(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
- begin
- for Result := Low(AValues) to High(AValues) do
- if (avalues[Result] = AText) Then
- exit; // make sure it is the first val.
- Result := -1;
- end;
- function IndexText(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
- begin
- for Result:=Low(AValues) to High(AValues) do
- if UnicodeCompareText(avalues[Result],atext)=0 Then
- exit; // make sure it is the first val.
- Result:=-1;
- end;
- operator in(const AText: AnsiString; const AValues: array of AnsiString): Boolean;
- begin
- Result := AnsiIndexStr(AText,AValues) <>-1;
- end;
- operator in(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
- begin
- Result := IndexStr(AText,AValues) <> -1;
- end;
- { ---------------------------------------------------------------------
- Playthingies
- ---------------------------------------------------------------------}
- function DupeString(const AText: string; ACount: Integer): string;
- var
- ResLen, Rp, ToCopy: SizeInt;
- begin
- if (AText = '') or (ACount <= 0) then
- Exit('');
- if ACount = 1 then
- Exit(AText);
- Rp := Length(AText);
- ResLen := ACount * Rp;
- SetLength(Result, ResLen);
- Move(Pointer(AText)^, Pointer(Result)^, Rp * SizeOf(AText[1]));
- repeat
- ToCopy := ResLen - Rp;
- if Rp < ToCopy then
- ToCopy := Rp;
- Move(Pointer(Result)^, PChar(Pointer(Result))[Rp], ToCopy * SizeOf(AText[1]));
- Inc(Rp, ToCopy);
- until Rp = ResLen;
- end;
- function ReverseString(const AText: string): string;
- var
- i,j : SizeInt;
- begin
- setlength(result,length(atext));
- i:=1; j:=length(atext);
- while (i<=j) do
- begin
- result[i]:=atext[j-i+1];
- inc(i);
- end;
- end;
- function AnsiReverseString(const AText: AnsiString): AnsiString;
- begin
- Result:=ReverseString(AText);
- end;
- function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
- var i,j,k : SizeUInt;
- begin
- j:=length(ASubText);
- i:=length(AText);
- if AStart>i then
- aStart:=i+1;
- k:=i+1-AStart;
- if ALength> k then
- ALength:=k;
- SetLength(Result,i+j-ALength);
- move (AText[1],result[1],(AStart-1)*SizeOf(Char));
- move (ASubText[1],result[AStart],j*SizeOf(Char));
- move (AText[AStart+ALength], Result[AStart+j],(i+1-AStart-ALength)*SizeOf(Char));
- end;
- function RandomFrom(const AValues: array of string): string;
- begin
- if high(AValues)=-1 then exit('');
- result:=Avalues[random(High(AValues)+1)];
- end;
- function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string): string;
- begin
- if avalue then
- result:=atrue
- else
- result:=afalse;
- end;
- Function IfThen(AValue: Boolean; const ATrue: TStringDynArray; const AFalse: TStringDynArray = nil): TStringDynArray; overload;
- begin
- if avalue then
- result:=atrue
- else
- result:=afalse;
- end;
- function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: AnsiChar): Integer;
- {
- NaturalCompareBase compares strings in a collated order and
- so numbers are sorted too. It sorts like this:
- 01
- 001
- 0001
- and
- 0
- 00
- 000
- 000_A
- 000_B
- in a intuitive order.
- }
- var
- Num1, Num2: double;
- pStr1, pStr2: PAnsiChar;
- Len1, Len2: SizeInt;
- TextLen1, TextLen2: SizeInt;
- TextStr1: string = '';
- TextStr2: string = '';
- i: SizeInt;
- j: SizeInt;
-
- function Sign(const AValue: sizeint): integer;inline;
- begin
- If Avalue<0 then
- Result:=-1
- else If Avalue>0 then
- Result:=1
- else
- Result:=0;
- end;
- function IsNumber(ch: AnsiChar): boolean;
- begin
- Result := ch in ['0'..'9'];
- end;
- function GetInteger(var pch: PAnsiChar; var Len: sizeint): double;
- begin
- Result := 0;
- while (pch^ <> #0) and IsNumber(pch^) do
- begin
- Result := Result * 10 + Ord(pch^) - Ord('0');
- Inc(Len);
- Inc(pch);
- end;
- end;
- procedure GetChars;
- begin
- TextLen1 := 0;
- while not ((pStr1 + TextLen1)^ in ['0'..'9']) and ((pStr1 + TextLen1)^ <> #0) do
- Inc(TextLen1);
- SetLength(TextStr1, TextLen1);
- i := 1;
- j := 0;
- while i <= TextLen1 do
- begin
- TextStr1[i] := (pStr1 + j)^;
- Inc(i);
- Inc(j);
- end;
- TextLen2 := 0;
- while not ((pStr2 + TextLen2)^ in ['0'..'9']) and ((pStr2 + TextLen2)^ <> #0) do
- Inc(TextLen2);
- SetLength(TextStr2, TextLen2);
- i := 1;
- j := 0;
- while i <= TextLen2 do
- begin
- TextStr2[i] := (pStr2 + j)^;
- Inc(i);
- Inc(j);
- end;
- end;
- begin
- if (Str1 <> '') and (Str2 <> '') then
- begin
- pStr1 := PAnsiChar(Str1);
- pStr2 := PAnsiChar(Str2);
- Result := 0;
- while not ((pStr1^ = #0) or (pStr2^ = #0)) do
- begin
- TextLen1 := 1;
- TextLen2 := 1;
- Len1 := 0;
- Len2 := 0;
- while (pStr1^ = ' ') do
- begin
- Inc(pStr1);
- Inc(Len1);
- end;
- while (pStr2^ = ' ') do
- begin
- Inc(pStr2);
- Inc(Len2);
- end;
- if IsNumber(pStr1^) and IsNumber(pStr2^) then
- begin
- Num1 := GetInteger(pStr1, Len1);
- Num2 := GetInteger(pStr2, Len2);
- if Num1 < Num2 then
- Result := -1
- else if Num1 > Num2 then
- Result := 1
- else
- begin
- Result := Sign(Len1 - Len2);
- end;
- Dec(pStr1);
- Dec(pStr2);
- end
- else
- begin
- GetChars;
- if TextStr1 <> TextStr2 then
- Result := WideCompareText(UTF8Decode(TextStr1), UTF8Decode(TextStr2))
- else
- Result := 0;
- end;
- if Result <> 0 then
- Break;
- Inc(pStr1, TextLen1);
- Inc(pStr2, TextLen2);
- end;
- end;
- Num1 := Length(Str1);
- Num2 := Length(Str2);
- if (Result = 0) and (Num1 <> Num2) then
- begin
- if Num1 < Num2 then
- Result := -1
- else
- Result := 1;
- end;
- end;
- function SplitString(const S, Delimiters: string): TRTLStringDynArray;
- Var
- a : Array of Char;
- I : Integer;
-
- begin
- SetLength(A,Length(Delimiters));
- For I:=1 to Length(Delimiters) do
- A[I-1]:=Delimiters[i];
- Result := S.Split(A);
- end;
- function NaturalCompareText (const S1 , S2 : string ): Integer ;
- begin
- Result := NaturalCompareText(S1, S2,
- DefaultFormatSettings.DecimalSeparator,
- DefaultFormatSettings.ThousandSeparator);
- end;
- { ---------------------------------------------------------------------
- VB emulations.
- ---------------------------------------------------------------------}
- function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
- begin
- Result:=Copy(AText,1,ACount);
- end;
- function RightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
- var j,l:SizeInt;
- begin
- l:=length(atext);
- j:=ACount;
- if j>l then j:=l;
- Result:=Copy(AText,l-j+1,j);
- end;
- function MidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;
- begin
- if (ACount=0) or (AStart>length(atext)) then
- exit('');
- Result:=Copy(AText,AStart,ACount);
- end;
- function LeftBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;
- begin
- Result:=LeftStr(AText,AByteCount);
- end;
- function RightBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;
- begin
- Result:=RightStr(Atext,AByteCount);
- end;
- function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: SizeInt): AnsiString;
- begin
- Result:=MidStr(AText,AByteStart,AByteCount);
- end;
- function AnsiLeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
- begin
- Result := copy(AText,1,ACount);
- end;
- function AnsiRightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
- begin
- Result := copy(AText,length(AText)-ACount+1,ACount);
- end;
- function AnsiMidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;
- begin
- Result:=Copy(AText,AStart,ACount);
- end;
- function LeftStr(const AText: WideString; const ACount: SizeInt): WideString;
- begin
- Result:=Copy(AText,1,ACount);
- end;
- function RightStr(const AText: WideString; const ACount: SizeInt): WideString;
- var
- j,l:SizeInt;
- begin
- l:=length(atext);
- j:=ACount;
- if j>l then j:=l;
- Result:=Copy(AText,l-j+1,j);
- end;
- function MidStr(const AText: WideString; const AStart, ACount: SizeInt): WideString;
- begin
- Result:=Copy(AText,AStart,ACount);
- end;
- { ---------------------------------------------------------------------
- Extended search and replace
- ---------------------------------------------------------------------}
- type
- TEqualFunction = function (const a,b : AnsiChar) : boolean;
- function EqualWithCase (const a,b : AnsiChar) : boolean;
- begin
- result := (a = b);
- end;
- function EqualWithoutCase (const a,b : AnsiChar) : boolean;
- begin
- result := (lowerCase(a) = lowerCase(b));
- end;
- function IsWholeWord (bufstart, bufend, wordstart, wordend : PAnsiChar) : boolean;
- begin
- // Check start
- result := ((wordstart = bufstart) or ((wordstart-1)^ in worddelimiters)) and
- // Check end
- ((wordend = bufend) or ((wordend+1)^ in worddelimiters));
- end;
- function SearchDown(buf,aStart,endchar:PAnsiChar; SearchString:string;
- Equals : TEqualFunction; WholeWords:boolean) : PAnsiChar;
- var Found : boolean;
- s, c : PAnsiChar;
- begin
- result := aStart;
- Found := false;
- while not Found and (result <= endchar) do
- begin
- // Search first letter
- while (result <= endchar) and not Equals(result^,SearchString[1]) do
- inc (result);
- // Check if following is searchstring
- c := result;
- s := @(Searchstring[1]);
- Found := true;
- while (c <= endchar) and (s^ <> #0) and Found do
- begin
- Found := Equals(c^, s^);
- inc (c);
- inc (s);
- end;
- if s^ <> #0 then
- Found := false;
- // Check if it is a word
- if Found and WholeWords then
- Found := IsWholeWord(buf,endchar,result,c-1);
- if not found then
- inc (result);
- end;
- if not Found then
- result := nil;
- end;
- function SearchUp(buf,aStart,endchar:PAnsiChar; SearchString:string;
- equals : TEqualFunction; WholeWords:boolean) : PAnsiChar;
- var Found : boolean;
- s, c, l : PAnsiChar;
- begin
- result := aStart;
- Found := false;
- l := @(SearchString[length(SearchString)]);
- while not Found and (result >= buf) do
- begin
- // Search last letter
- while (result >= buf) and not Equals(result^,l^) do
- dec (result);
- // Check if before is searchstring
- c := result;
- s := l;
- Found := true;
- while (c >= buf) and (s >= @SearchString[1]) and Found do
- begin
- Found := Equals(c^, s^);
- dec (c);
- dec (s);
- end;
- if (s >= @(SearchString[1])) then
- Found := false;
- // Check if it is a word
- if Found and WholeWords then
- Found := IsWholeWord(buf,endchar,c+1,result);
- if found then
- result := c+1
- else
- dec (result);
- end;
- if not Found then
- result := nil;
- end;
- //function SearchDown(buf,aStart,endchar:PAnsiChar; SearchString:string; equal : TEqualFunction; WholeWords:boolean) : PAnsiChar;
- function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String; Options: TStringSearchOptions
- ): PAnsiChar;
- var
- equal : TEqualFunction;
- begin
- SelStart := SelStart + SelLength;
- if (SearchString = '') or (SelStart > BufLen) or (SelStart < 0) then
- result := nil
- else
- begin
- if soMatchCase in Options then
- Equal := @EqualWithCase
- else
- Equal := @EqualWithoutCase;
- if soDown in Options then
- result := SearchDown(buf,buf+SelStart,Buf+(BufLen-1), SearchString, Equal, (soWholeWord in Options))
- else
- result := SearchUp(buf,buf+SelStart,Buf+(Buflen-1), SearchString, Equal, (soWholeWord in Options));
- end;
- end;
- function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String): PAnsiChar; // ; Options: TStringSearchOptions = [soDown]
- begin
- Result:=SearchBuf(Buf,BufLen,SelStart,SelLength,SearchString,[soDown]);
- end;
- function PosEx(const SubStr, S: AnsiString; Offset: SizeInt): SizeInt;
- begin
- Result := Pos(SubStr, S, Offset);
- end;
- function PosEx(c: AnsiChar; const S: Ansistring; Offset: SizeInt): SizeInt;
- begin
- Result := Pos(c, S, Offset);
- end;
- function PosEx(const SubStr, S: Ansistring): SizeInt;
- begin
- Result := Pos(SubStr, S);
- end;
- function PosEx(const SubStr, S: UnicodeString; Offset: SizeInt): SizeInt;
- begin
- Result := Pos(SubStr, S, Offset);
- end;
- function PosEx(c: WideChar; const S: UnicodeString; Offset: SizeInt): SizeInt;
- begin
- Result := Pos(c, S, Offset);
- end;
- function PosEx(const SubStr, S: UnicodeString): Sizeint;
- begin
- Result := Pos(SubStr, S);
- end;
- function StringsReplace(const S: AnsiString; OldPattern, NewPattern: array of AnsiString; Flags: TReplaceFlags): string;
- var pc,lastpc,litStart : PAnsiChar;
- iPattern,Rp,Ra,iFirstPattern,OldPatternLen : SizeInt;
- // Heads of the linked lists of patterns starting with a character whose code has this residue modulo length(firstPattern).
- // Length must be power of two, less = slower for large cases, more = slower for small cases.
- // 0 .. 255 (or directly [AnsiChar]) might be a bit too much because the array is initialized every time; and generalizes worse to S: UnicodeString :)
- firstPattern : array[0 .. 63] of SizeInt;
- nextPattern : PSizeInt; // Next pattern starting with the same character.
- nextPatternStatic: array[0 .. 63] of SizeInt;
- CompStr : ansistring;
- {$if sizeof(char) <> sizeof(ansichar)}
- tempStr : string;
- {$endif}
- procedure Append(P: PChar; N: SizeInt);
- begin
- if N>Ra-Rp then
- begin
- Ra:=Rp+N+4+Ra shr 1+Ra shr 2; // + N + const + 37.5%
- SetLength(Result,Ra);
- end;
- Move(P^,PChar(Pointer(Result))[Rp],N*SizeOf(Char));
- Rp:=Rp+N;
- end;
- // Mostly exists to force better register allocation for the main "pc < lastpc" loop, hotter than this procedure. :)
- // Returns the length of the found and replaced OldPattern item, or -1 if not found.
- function TryMatchAndReplace(pc,lastpc: PAnsiChar; iPattern: SizeInt): SizeInt;
- var
- pcc: PAnsiChar;
- OldPatternLen: SizeInt;
- begin
- repeat
- OldPatternLen:=Length(OldPattern[iPattern]);
- if (OldPatternLen <= (lastpc-pc)) and
- (CompareByte(OldPattern[iPattern,1],pc^,OldPatternLen*SizeOf(AnsiChar))=0) then
- begin
- pcc:=PAnsiChar(Pointer(S))+(pc-PAnsiChar(Pointer(CompStr)));
- {$if sizeof(char)=sizeof(ansichar)}
- Append(litStart,pcc-litStart);
- Append(PChar(Pointer(NewPattern[iPattern])), Length(NewPattern[iPattern]));
- {$else}
- tempStr := Copy(S,1+litStart-PAnsiChar(Pointer(S)),pcc-litStart);
- Append(PChar(Pointer(tempStr)), Length(tempStr));
- tempStr := NewPattern[iPattern];
- Append(PChar(Pointer(tempStr)), Length(tempStr));
- {$endif}
- litStart := pcc+OldPatternLen;
- exit(OldPatternLen);
- end;
- iPattern := nextPattern[iPattern];
- until iPattern < 0;
- result := -1;
- end;
- begin
- if High(OldPattern) <> High(NewPattern) then
- raise exception.Create(SErrAmountStrings);
- FillChar(firstPattern, sizeof(firstPattern), byte(-1));
- if High(OldPattern) <= High(nextPatternStatic) then
- nextPattern := PSizeInt(nextPatternStatic)
- else
- nextPattern := GetMem(Length(OldPattern) * sizeof(SizeInt));
- FillChar(nextPattern^, Length(OldPattern) * sizeof(SizeInt), byte(-1));
- if rfIgnoreCase in Flags then
- begin
- CompStr := AnsiUpperCase(S);
- for iPattern := 0 to High(OldPattern) do
- OldPattern[iPattern] := AnsiUpperCase(OldPattern[iPattern]);
- end
- else
- CompStr := S;
- // The element added to the linked list last will be checked first, so add in reverse order.
- for iPattern := High(OldPattern) downto 0 do
- if OldPattern[iPattern] <> '' then
- begin
- iFirstPattern := ord(OldPattern[iPattern,1]) and High(firstPattern);
- nextPattern[iPattern] := firstPattern[iFirstPattern];
- firstPattern[iFirstPattern] := iPattern;
- end;
- Ra := Length(S); // Preallocation heuristic.
- SetLength(result, Ra);
- Rp := 0;
- pc := PAnsiChar(Pointer(CompStr));
- litStart := PAnsiChar(Pointer(S));
- lastpc := pc+Length(S);
- while pc < lastpc do
- begin
- iPattern := firstPattern[ord(pc^) and High(firstPattern)];
- inc(pc);
- if iPattern >= 0 then
- begin
- OldPatternLen := TryMatchAndReplace(pc-1, lastpc, iPattern);
- if OldPatternLen >= 0 then
- begin
- pc := pc-1+OldPatternLen;
- if not (rfReplaceAll in Flags) then
- break;
- end;
- end;
- end;
- if nextPattern <> PSizeInt(nextPattern) then
- FreeMem(nextPattern);
- if litStart = PAnsiChar(Pointer(S)) then
- exit(S); // Unchanged string.
- {$if sizeof(char)=sizeof(ansichar)}
- Append(litStart,PAnsiChar(Pointer(S))+(lastpc-PAnsiChar(Pointer(CompStr)))-litStart);
- {$else}
- tempStr := Copy(S,1+litStart-PAnsiChar(Pointer(S)),PAnsiChar(Pointer(S))+(lastpc-PAnsiChar(Pointer(CompStr)))-litStart);
- Append(PChar(Pointer(tempStr)), Length(tempStr));
- {$endif}
- SetLength(result,Rp);
- end;
- { ---------------------------------------------------------------------
- Delphi compat
- ---------------------------------------------------------------------}
- function ReplaceStr(const AText, AFromText, AToText: string): string;
- begin
- result:=AnsiReplaceStr(AText, AFromText, AToText);
- end;
- function ReplaceText(const AText, AFromText, AToText: string): string;
- begin
- result:=AnsiReplaceText(AText, AFromText, AToText);
- end;
- { ---------------------------------------------------------------------
- Soundex Functions.
- ---------------------------------------------------------------------}
- Const
- SScore : array[1..255] of AnsiChar =
- ('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
- '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
- '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
- '0','0','0','0','0','0', // 91..96
- '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
- '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
- '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
- '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
- '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
- '0','0','0','0','0'); // 251..255
- function Soundex(const AText: string; ALength: TSoundexLength): string;
- Var
- S,PS : AnsiChar;
- I,L : SizeInt;
- begin
- Result:='';
- PS:=#0;
- If Length(AText)>0 then
- begin
- Result:=Upcase(AText[1]);
- I:=2;
- L:=Length(AText);
- While (I<=L) and (Length(Result)<ALength) do
- begin
- S:=SScore[Ord(AText[i])];
- If Not (S in ['0','i',PS]) then
- Result:=Result+S;
- If (S<>'i') then
- PS:=S;
- Inc(I);
- end;
- end;
- L:=Length(Result);
- If (L<ALength) then
- Result:=Result+StringOfChar('0',Alength-L);
- end;
- function Soundex(const AText: string): string; // ; ALength: TSoundexLength = 4
- begin
- Result:=Soundex(AText,4);
- end;
- Const
- Ord0 = Ord('0');
- OrdA = Ord('A');
- function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
- var
- SE: string;
- I: SizeInt;
- begin
- Result:=-1;
- SE:=Soundex(AText,ALength);
- If Length(SE)>0 then
- begin
- Result:=Ord(SE[1])-OrdA;
- if ALength > 1 then
- begin
- Result:=Result*26+(Ord(SE[2])-Ord0);
- for I:=3 to ALength do
- Result:=(Ord(SE[I])-Ord0)+Result*7;
- end;
- Result:=ALength+Result*9;
- end;
- end;
- function SoundexInt(const AText: string): Integer; //; ALength: TSoundexIntLength = 4
- begin
- Result:=SoundexInt(AText,4);
- end;
- function DecodeSoundexInt(AValue: Integer): string;
- var
- I, Len: Integer;
- begin
- Result := '';
- Len := AValue mod 9;
- AValue := AValue div 9;
- for I:=Len downto 3 do
- begin
- Result:=Chr(Ord0+(AValue mod 7))+Result;
- AValue:=AValue div 7;
- end;
- if Len>1 then
- begin
- Result:=Chr(Ord0+(AValue mod 26))+Result;
- AValue:=AValue div 26;
- end;
- Result:=Chr(OrdA+AValue)+Result;
- end;
- function SoundexWord(const AText: string): Word;
- Var
- S : String;
- begin
- S:=SoundEx(Atext,4);
- Result:=Ord(S[1])-OrdA;
- Result:=Result*26+ord(S[2])-48;
- Result:=Result*7+ord(S[3])-48;
- Result:=Result*7+ord(S[4])-48;
- end;
- function DecodeSoundexWord(AValue: Word): string;
- begin
- Result := Chr(Ord0+ (AValue mod 7));
- AValue := AValue div 7;
- Result := Chr(Ord0+ (AValue mod 7)) + Result;
- AValue := AValue div 7;
- Result := IntToStr(AValue mod 26) + Result;
- AValue := AValue div 26;
- Result := Chr(OrdA+AValue) + Result;
- end;
- function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;
- begin
- Result:=Soundex(AText,ALength)=Soundex(AOther,ALength);
- end;
- function SoundexSimilar(const AText, AOther: string): Boolean; //; ALength: TSoundexLength = 4
- begin
- Result:=SoundexSimilar(AText,AOther,4);
- end;
- function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;
- begin
- Result:=AnsiCompareStr(Soundex(AText,ALength),Soundex(AOther,ALength));
- end;
- function SoundexCompare(const AText, AOther: string): Integer; //; ALength: TSoundexLength = 4
- begin
- Result:=SoundexCompare(AText,AOther,4);
- end;
- function SoundexProc(const AText, AOther: string): Boolean;
- begin
- Result:=SoundexSimilar(AText,AOther);
- end;
- { ---------------------------------------------------------------------
- RxStrUtils-like functions.
- ---------------------------------------------------------------------}
- function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
- var
- i,l: SizeInt;
- begin
- l:=Length(S);
- i:=1;
- Result:=True;
- while Result and (i<=l) do
- begin
- Result:=(S[i] in EmptyChars);
- Inc(i);
- end;
- end;
- function DelSpace(const S: string): string;
- begin
- Result:=DelChars(S,' ');
- end;
- function IndexCharSized(p: PChar; nchars: SizeInt; charv: SizeUint): SizeInt; inline;
- begin
- result :=
- {$if sizeof(char) = sizeof(byte)} IndexByte
- {$elseif sizeof(char) = sizeof(word)} IndexWord
- {$else} {$error unknown char size}
- {$endif}
- (p^, nchars, charv);
- end;
- procedure FillCharSized(p: PChar; nchars: SizeInt; charv: SizeUint); inline;
- begin
- {$if sizeof(char) = sizeof(byte)} FillChar
- {$elseif sizeof(char) = sizeof(word)} FillWord
- {$else} {$error unknown char size}
- {$endif}
- (p^, nchars, charv);
- end;
- function DelChars(const S: string; Chr: Char): string;
- var
- Sp, Se, Rp: PChar;
- ToCopy: SizeInt;
- begin
- Sp := PChar(Pointer(S));
- Se := Sp + Length(S);
- ToCopy := IndexCharSized(Sp, SizeUint(Pointer(Se) - Pointer(Sp)) div sizeof(Char), ord(Chr));
- if ToCopy < 0 then
- exit(S); // Unchanged string.
- SetLength(result, SizeUint(Pointer(Se) - Pointer(Sp)) div sizeof(Char));
- Rp := PChar(Pointer(Result));
- repeat
- Move(Sp^, Rp^, ToCopy * sizeof(Char));
- Inc(Sp, ToCopy);
- Inc(Rp, ToCopy);
- repeat
- Inc(Sp); // Can increment to Se + 1.
- until (Sp >= Se) or (Sp^ <> Chr);
- if Sp >= Se then
- break;
- ToCopy := IndexCharSized(Sp, SizeUint(Pointer(Se) - Pointer(Sp)) div sizeof(Char), ord(Chr));
- if ToCopy < 0 then
- ToCopy := SizeUint(Pointer(Se) - Pointer(Sp)) div sizeof(Char);
- until false;
- SetLength(result, SizeUint(Pointer(Rp) - Pointer(Result)) div sizeof(Char));
- end;
- function DelChars(const S: string; Chars: TSysCharSet): string;
- var
- Ss, Sp, Se, Rp: PChar;
- aDelta : Integer;
-
- begin
- Ss := PChar(Pointer(S));
- Sp := Ss;
- Se := Sp + Length(S);
- while (Sp < Se) and not (Sp^ in Chars) do
- Inc(Sp);
- if Sp >= Se then
- Exit(S); // Unchanged string.
- SetLength(result, SizeUint(Pointer(Se) - Pointer(Ss)) div sizeof(Char));
- Rp := PChar(Pointer(Result));
- repeat
- aDelta:=(Pointer(Sp) - Pointer(Ss));
- Move(Ss^, Rp^, aDelta);
- Inc(Pointer(Rp), aDelta);
- repeat
- Inc(Sp); // Can increment to Se + 1.
- until (Sp >= Se) or not (Sp^ in Chars);
- if Sp >= Se then
- break;
- Ss := Sp;
- repeat
- Inc(Sp);
- until (Sp >= Se) or (Sp^ in Chars);
- until false;
- SetLength(result, SizeUint(Pointer(Rp) - Pointer(Result)) div sizeof(Char));
- end;
- function FindSpacePrecededBySpace(Sp, Se: PChar): PChar;
- var
- SpacePos: SizeInt;
- begin
- repeat
- SpacePos := IndexCharSized(Sp, SizeUint(Pointer(Se) - Pointer(Sp)) div sizeof(Char), ord(' '));
- if SpacePos < 0 then
- Exit(Se);
- Inc(Sp, SpacePos+1);
- until (Sp>=Se) or (Sp^=' ');
- Result:=Sp;
- end;
- function DelSpace1(const S: string): string;
- var
- Ss, Sp, Se, Rp: PChar;
- begin
- Ss := PChar(Pointer(S));
- Se := Ss + Length(S);
- Sp := FindSpacePrecededBySpace(Ss, Se);
- if Sp >= Se then
- Exit(S); // Unchanged string.
- SetLength(result, SizeUint(Pointer(Se) - Pointer(Ss)) div sizeof(Char));
- Rp := PChar(Pointer(Result));
- repeat
- Move(Ss^, Rp^, Pointer(Sp) - Pointer(Ss));
- Inc(Pointer(Rp), Pointer(Sp) - Pointer(Ss));
- repeat
- Inc(Sp); // Can increment to Se + 1.
- until (Sp >= Se) or (Sp^ <> ' ');
- if Sp >= Se then
- break;
- Ss := Sp;
- Sp := FindSpacePrecededBySpace(Sp, Se);
- until false;
- SetLength(result, SizeUint(Pointer(Rp) - Pointer(Result)) div sizeof(Char));
- end;
- function Tab2Space(const S: string; Numb: Byte): string;
- var
- I: SizeInt;
- begin
- I:=1;
- Result:=S;
- while I <= Length(Result) do
- if Result[I]<>Chr(9) then
- inc(I)
- else
- begin
- Result[I]:=' ';
- If (Numb>1) then
- Insert(StringOfChar(' ',Numb-1),Result,I);
- Inc(I,Numb);
- end;
- end;
- function NPos(const C: string; const S: string; N: Integer): SizeInt;
- begin
- Result:=0;
- if N>=1 then
- Repeat
- Result:=Pos(C,S,Result+1);
- dec(N);
- until (N=0) or (Result=0);
- end;
- function AddChar(C: AnsiChar; const S: string; N: Integer): string;
- Var
- l : SizeInt;
- begin
- l:=Length(S);
- if l>=N then
- Exit(S);
- SetLength(Result,N);
- FillCharSized(Pointer(Result),N-l,ord(C));
- Move(Pointer(S)^,PChar(Pointer(Result))[N-l],l*sizeof(Char));
- end;
- function AddCharR(C: AnsiChar; const S: string; N: Integer): string;
- Var
- l : SizeInt;
- begin
- l:=Length(S);
- if l>=N then
- Exit(S);
- SetLength(Result,N);
- Move(Pointer(S)^,Pointer(Result)^,l*sizeof(Char));
- FillCharSized(PChar(Pointer(Result))+l,N-l,ord(C));
- end;
- function PadRight(const S: string; N: Integer): string;inline;
- begin
- Result:=AddCharR(' ',S,N);
- end;
- function PadLeft(const S: string; N: Integer): string;inline;
- begin
- Result:=AddChar(' ',S,N);
- end;
- function Copy2Symb(const S: string; Symb: AnsiChar): string;
- var
- p: SizeInt;
- begin
- p:=Pos(Symb,S);
- if p=0 then
- p:=Length(S)+1;
- Result:=Copy(S,1,p-1);
- end;
- function Copy2SymbDel(var S: string; Symb: AnsiChar): string;
- var
- p: SizeInt;
- begin
- p:=Pos(Symb,S);
- if p=0 then
- begin
- result:=s;
- s:='';
- end
- else
- begin
- Result:=Copy(S,1,p-1);
- delete(s,1,p);
- end;
- end;
- function Copy2Space(const S: string): string;inline;
- begin
- Result:=Copy2Symb(S,' ');
- end;
- function Copy2SpaceDel(var S: string): string;inline;
- begin
- Result:=Copy2SymbDel(S,' ');
- end;
- function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
- var
- P,PE : PAnsiChar;
- begin
- Result:=AnsiLowerCase(S);
- P:=PAnsiChar(pointer(Result));
- PE:=P+Length(Result);
- while (P<PE) do
- begin
- while (P<PE) and (P^ in WordDelims) do
- inc(P);
- if (P<PE) then
- P^:=UpCase(P^);
- while (P<PE) and not (P^ in WordDelims) do
- inc(P);
- end;
- end;
- function WordCount(const S: string; const WordDelims: TSysCharSet): SizeInt;
- var
- P,PE : PAnsiChar;
- WasDelim, NowDelim : Boolean;
- begin
- Result:=0;
- P:=PAnsiChar(pointer(S));
- PE:=P+Length(S);
- WasDelim:=true;
- while (P<PE) do
- begin
- NowDelim := P^ in WordDelims;
- Inc(Result,ord(WasDelim and not NowDelim));
- WasDelim := NowDelim;
- Inc(P);
- end;
- end;
- function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): SizeInt;
- var
- P,PE : PChar;
- Count: Integer;
- begin
- P:=PChar(pointer(S));
- PE:=P+Length(S);
- Count:=N;
- while (P<PE) and (P^ in WordDelims) do
- Inc(P);
- while (P<PE) do
- begin
- Dec(Count);
- if Count<=0 then
- break;
- repeat
- Inc(P);
- until (P>=PE) or (P^ in WordDelims);
- repeat
- Inc(P); // Can increment to PE + 1.
- until (P>=PE) or not (P^ in WordDelims);
- end;
- if (P<PE) and (Count=0) then
- exit(P-PChar(pointer(S))+1);
- Result:=0;
- end;
- function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
- var
- i: SizeInt;
- begin
- Result:=ExtractWordPos(N,S,WordDelims,i);
- end;
- function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: Integer): string;
- var
- i,j: SizeInt;
- begin
- i:=WordPosition(N, S, WordDelims);
- if not ((I>0) and (I<=High(Integer))) then
- begin
- Result:='';
- Pos:=0;
- Exit;
- end;
- Pos:=i;
- j:=PosSetEx(WordDelims, S, i+1);
- if j=0 then
- j:=Length(S)+1;
- Result:=Copy(S,i,j-i);
- end;
- {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
- function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; Out Pos: SizeInt): string;
- var
- i,j: SizeInt;
- begin
- i:=WordPosition(N, S, WordDelims);
- Pos:=i;
- if I<=0 then
- begin
- Result:='';
- Exit;
- end;
- j:=PosSetEx(WordDelims, S, i+1);
- if j=0 then
- j:=Length(S)+1;
- Result:=Copy(S,i,j-i);
- end;
- {$ENDIF}
- function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
- var
- i,start,len: SizeInt;
- begin
- i:=1;
- len:=Length(S);
- while (i<=len) and (N>1) do
- begin
- dec(N,ord(S[i] in Delims));
- inc(i);
- end;
- if N<>1 then
- exit('');
- start:=i;
- while (i<=len) and not (S[i] in Delims) do
- inc(i);
- exit(Copy(S,start,i-start));
- end;
- {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
- function ExtractSubstr(const S: string; var Pos: SizeInt; const Delims: TSysCharSet): string;
- var
- i,l: SizeInt;
- begin
- i:=Pos;
- l:=Length(S);
- while (i<=l) and not (S[i] in Delims) do
- inc(i);
- Result:=Copy(S,Pos,i-Pos);
- while (i<=l) and (S[i] in Delims) do
- inc(i);
- Pos:=i;
- end;
- {$ENDIF}
- function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
- var
- i,l: SizeInt;
- begin
- i:=Pos;
- l:=Length(S);
- while (i<=l) and not (S[i] in Delims) do
- inc(i);
- Result:=Copy(S,Pos,i-Pos);
- while (i<=l) and (S[i] in Delims) do
- inc(i);
- if I>MaxInt then
- Pos:=MaxInt
- else
- Pos:=i;
- end;
- function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
- var
- P,PE,WordStart : PChar;
- Wbytes : SizeInt;
- begin
- Wbytes:=Length(W)*sizeof(char);
- P:=PChar(pointer(S));
- PE:=P+Length(S);
- while (P<PE) and (P^ in WordDelims) do
- Inc(P);
- while (P<PE) do
- begin
- WordStart:=P;
- repeat
- Inc(P);
- until (P>=PE) or (P^ in WordDelims);
- if (pointer(P)-pointer(WordStart)=Wbytes) and (CompareByte(Pointer(W)^,WordStart^,Wbytes)=0) then
- exit(true);
- repeat
- Inc(P); // Can increment to PE + 1.
- until (P>=PE) or not (P^ in WordDelims);
- end;
- result:=false;
- end;
- function Numb2USA(const S: string): string;
- var
- i, NA: Integer;
- begin
- i:=Length(S);
- Result:=S;
- NA:=0;
- while (i > 0) do begin
- if ((Length(Result) - i + 1 - NA) mod 3 = 0) and (i <> 1) then
- begin
- insert(',', Result, i);
- inc(NA);
- end;
- Dec(i);
- end;
- end;
- function PadCenter(const S: string; Len: SizeInt): string;
- var
- Ns,Nfirstspaces: SizeInt;
- begin
- Ns:=Length(S);
- if Ns>=Len then
- exit(S);
- SetLength(Result,Len);
- Nfirstspaces:=SizeUint(Len) div 2-SizeUint(Ns) div 2;
- FillCharSized(Pointer(Result),Nfirstspaces,ord(' '));
- FillCharSized(PChar(Pointer(Result))+Ns+Nfirstspaces,Len-Ns-Nfirstspaces,ord(' '));
- Move(Pointer(S)^,PChar(Pointer(Result))[Nfirstspaces],Ns*sizeof(char));
- end;
- function Dec2Numb(N: Longint; Len, Base: Byte): string;
- var
- C: Integer;
- Number: Longint;
- begin
- if N=0 then
- Result:='0'
- else
- begin
- Number:=N;
- Result:='';
- while Number>0 do
- begin
- C:=Number mod Base;
- if C>9 then
- C:=C+55
- else
- C:=C+48;
- Result:=Chr(C)+Result;
- Number:=Number div Base;
- end;
- end;
- if (Result<>'') then
- Result:=AddChar('0',Result,Len);
- end;
- function Numb2Dec(S: string; Base: Byte): Longint;
- var
- i, P: sizeint;
- begin
- i:=Length(S);
- Result:=0;
- S:=UpperCase(S);
- P:=1;
- while (i>=1) do
- begin
- if (S[i]>'@') then
- Result:=Result+(Ord(S[i])-55)*P
- else
- Result:=Result+(Ord(S[i])-48)*P;
- Dec(i);
- P:=P*Base;
- end;
- end;
- function RomanToIntDontCare(const S: String): Longint;
- {This was the original implementation of RomanToInt,
- it is internally used in TryRomanToInt when Strictness = rcsDontCare}
- const
- RomanChars = ['C','D','I','L','M','V','X'];
- RomanValues : array['C'..'X'] of Word
- = (100,500,0,0,0,0,1,0,0,50,1000,0,0,0,0,0,0,0,0,5,0,10);
- var
- index, Next: AnsiChar;
- i,l: SizeInt;
- Negative: Boolean;
- begin
- Result:=0;
- i:=0;
- Negative:=(Length(S)>0) and (S[1]='-');
- if Negative then
- inc(i);
- l:=Length(S);
- while (i<l) do
- begin
- inc(i);
- index:=UpCase(S[i]);
- if index in RomanChars then
- begin
- if Succ(i)<=l then
- Next:=UpCase(S[i+1])
- else
- Next:=#0;
- if (Next in RomanChars) and (RomanValues[index]<RomanValues[Next]) then
- begin
- inc(Result, RomanValues[Next]);
- Dec(Result, RomanValues[index]);
- inc(i);
- end
- else
- inc(Result, RomanValues[index]);
- end
- else
- begin
- Result:=0;
- Exit;
- end;
- end;
- if Negative then
- Result:=-Result;
- end;
- { TryRomanToInt: try to convert a roman numeral to an integer
- Parameters:
- S: Roman numeral (like: 'MCMXXII')
- N: Integer value of S (only meaningfull if the function succeeds)
- Stricness: controls how strict the parsing of S is
- - rcsStrict:
- * Follow common subtraction rules
- - only 1 preceding subtraction character allowed: IX = 9, but IIX <> 8
- - from M you can only subtract C
- - from D you can only subtract C
- - from C you can only subtract X
- - from L you can only subtract X
- - from X you can only subtract I
- - from V you can only subtract I
- * The numeral is parsed in "groups" (first M's, then D's etc.), the next group to be parsed
- must always be of a lower denomination than the previous one.
- Example: 'MMDCCXX' is allowed but 'MMCCXXDD' is not
- * There can only ever be 3 consecutive M's, C's, X's or I's
- * There can only ever be 1 D, 1 L and 1 V
- * After IX or IV there can be no more characters
- * Negative numbers are not supported
- // As a consequence the maximum allowed Roman numeral is MMMCMXCIX = 3999, also N can never become 0 (zero)
- - rcsRelaxed: Like rcsStrict but with the following exceptions:
- * An infinite number of (leading) M's is allowed
- * Up to 4 consecutive M's, C's, X's and I's are allowed
- // So this is allowed: 'MMMMMMCXIIII' = 6124
- - rcsDontCare:
- * no checking on the order of "groups" is done
- * there are no restrictions on the number of consecutive chars
- * negative numbers are supported
- * an empty string as input will return True and N will be 0
- * invalid input will return false
- // for backwards comatibility: it supports rather ludicrous input like '-IIIMIII' -> -(2+(1000-1)+3)=-1004
- }
- function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
- var
- i, Len: SizeInt;
- Terminated: Boolean;
- begin
- Result := (False);
- S := UpperCase(S); //don't use AnsiUpperCase please
- Len := Length(S);
- if (Strictness = rcsDontCare) then
- begin
- N := RomanToIntDontCare(S);
- if (N = 0) then
- begin
- Result := (Len = 0);
- end
- else
- Result := True;
- Exit;
- end;
- if (Len = 0) then
- begin
- Result:=true;
- N:=0;
- Exit;
- end;
- i := 1;
- N := 0;
- Terminated := False;
- //leading M's
- while (i <= Len) and ((Strictness <> rcsStrict) or (i < 4)) and (S[i] = 'M') do
- begin
- //writeln('TryRomanToInt: Found 1000');
- Inc(i);
- N := N + 1000;
- end;
- //then CM or or CD or D or (C, CC, CCC, CCCC)
- if (i <= Len) and (S[i] = 'D') then
- begin
- //writeln('TryRomanToInt: Found 500');
- Inc(i);
- N := N + 500;
- end
- else if (i + 1 <= Len) and (S[i] = 'C') then
- begin
- if (S[i+1] = 'M') then
- begin
- //writeln('TryRomanToInt: Found 900');
- Inc(i,2);
- N := N + 900;
- end
- else if (S[i+1] = 'D') then
- begin
- //writeln('TryRomanToInt: Found 400');
- Inc(i,2);
- N := N + 400;
- end;
- end ;
- //next max 4 or 3 C's, depending on Strictness
- if (i <= Len) and (S[i] = 'C') then
- begin
- //find max 4 C's
- //writeln('TryRomanToInt: Found 100');
- Inc(i);
- N := N + 100;
- if (i <= Len) and (S[i] = 'C') then
- begin
- //writeln('TryRomanToInt: Found 100');
- Inc(i);
- N := N + 100;
- end;
- if (i <= Len) and (S[i] = 'C') then
- begin
- //writeln('TryRomanToInt: Found 100');
- Inc(i);
- N := N + 100;
- end;
- if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'C') then
- begin
- //writeln('TryRomanToInt: Found 100');
- Inc(i);
- N := N + 100;
- end;
- end;
- //then XC or XL
- if (i + 1 <= Len) and (S[i] = 'X') then
- begin
- if (S[i+1] = 'C') then
- begin
- //writeln('TryRomanToInt: Found 90');
- Inc(i,2);
- N := N + 90;
- end
- else if (S[i+1] = 'L') then
- begin
- //writeln('TryRomanToInt: Found 40');
- Inc(i,2);
- N := N + 40;
- end;
- end;
- //then L
- if (i <= Len) and (S[i] = 'L') then
- begin
- //writeln('TryRomanToInt: Found 50');
- Inc(i);
- N := N + 50;
- end;
- //then (X, xx, xxx, xxxx)
- if (i <= Len) and (S[i] = 'X') then
- begin
- //find max 3 or 4 X's, depending on Strictness
- //writeln('TryRomanToInt: Found 10');
- Inc(i);
- N := N + 10;
- if (i <= Len) and (S[i] = 'X') then
- begin
- //writeln('TryRomanToInt: Found 10');
- Inc(i);
- N := N + 10;
- end;
- if (i <= Len) and (S[i] = 'X') then
- begin
- //writeln('TryRomanToInt: Found 10');
- Inc(i);
- N := N + 10;
- end;
- if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'X') then
- begin
- //writeln('TryRomanToInt: Found 10');
- Inc(i);
- N := N + 10;
- end;
- end;
- //then IX or IV
- if (i + 1 <= Len) and (S[i] = 'I') then
- begin
- if (S[i+1] = 'X') then
- begin
- Terminated := (True);
- //writeln('TryRomanToInt: Found 9');
- Inc(i,2);
- N := N + 9;
- end
- else if (S[i+1] = 'V') then
- begin
- Terminated := (True);
- //writeln('TryRomanToInt: Found 4');
- Inc(i,2);
- N := N + 4;
- end;
- end;
- //then V
- if (not Terminated) and (i <= Len) and (S[i] = 'V') then
- begin
- //writeln('TryRomanToInt: Found 5');
- Inc(i);
- N := N + 5;
- end;
- //then I
- if (not Terminated) and (i <= Len) and (S[i] = 'I') then
- begin
- Terminated := (True);
- //writeln('TryRomanToInt: Found 1');
- Inc(i);
- N := N + 1;
- //Find max 2 or 3 closing I's, depending on strictness
- if (i <= Len) and (S[i] = 'I') then
- begin
- //writeln('TryRomanToInt: Found 1');
- Inc(i);
- N := N + 1;
- end;
- if (i <= Len) and (S[i] = 'I') then
- begin
- //writeln('TryRomanToInt: Found 1');
- Inc(i);
- N := N + 1;
- end;
- if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'I') then
- begin
- //writeln('TryRomanToInt: Found 1');
- Inc(i);
- N := N + 1;
- end;
- end;
- //writeln('TryRomanToInt: Len = ',Len,' i = ',i);
- Result := (i > Len);
- //if Result then writeln('TryRomanToInt: N = ',N);
- end;
- function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
- begin
- if not TryRomanToInt(S, Result, Strictness) then
- raise EConvertError.CreateFmt(SInvalidRomanNumeral,[S]);
- end;
- function RomanToIntDef(const S: String; const ADefault: Longint;
- Strictness: TRomanConversionStrictness): Longint;
- begin
- if not TryRomanToInt(S, Result, Strictness) then
- Result := ADefault;
- end;
- function IntToRoman(Value: Longint): string;
- const
- Arabics : Array[1..13] of Integer
- = (1,4,5,9,10,40,50,90,100,400,500,900,1000);
- Romans : Array[1..13] of String
- = ('I','IV','V','IX','X','XL','L','XC','C','CD','D','CM','M');
- var
- i: Integer;
- begin
- Result:='';
- for i:=13 downto 1 do
- while (Value >= Arabics[i]) do
- begin
- Value:=Value-Arabics[i];
- Result:=Result+Romans[i];
- end;
- end;
- function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
- var endpos : integer;
- p,p2:PChar;
- k: integer;
- begin
- Result:='';
- if (Digits>32) then
- Digits:=32;
- if (spaces=0) then
- begin
- result:=inttobin(value,digits);
- exit;
- end;
- endpos:=digits+ (digits-1) div spaces;
- setlength(result,endpos);
- p:=@result[endpos];
- p2:=@result[1];
- k:=spaces;
- while (p>=p2) do
- begin
- if k=0 then
- begin
- p^:=' ';
- dec(p);
- k:=spaces;
- end;
- p^:=chr(48+(cardinal(value) and 1));
- value:=cardinal(value) shr 1;
- dec(p);
- dec(k);
- end;
- end;
- function IntToBin(Value: Longint; Digits: Integer): string;
- var p,p2 : PChar;
- begin
- result:='';
- if digits<=0 then exit;
- setlength(result,digits);
- p:=PChar(pointer(@result[digits]));
- p2:=PChar(pointer(@result[1]));
- // typecasts because we want to keep intto* delphi compat and take an integer
- while (p>=p2) and (cardinal(value)>0) do
- begin
- p^:=chr(48+(cardinal(value) and 1));
- value:=cardinal(value) shr 1;
- dec(p);
- end;
- digits:=p-p2+1;
- if digits>0 then
- fillchar(result[1],digits,#48);
- end;
- function intToBin(Value: int64; Digits:integer): string;
- var p,p2 : PChar;
- begin
- result:='';
- if digits<=0 then exit;
- setlength(result,digits);
- p:=PChar(pointer(@result[digits]));
- p2:=PChar(pointer(@result[1]));
- // typecasts because we want to keep intto* delphi compat and take a signed val
- // and avoid warnings
- while (p>=p2) and (qword(value)>0) do
- begin
- p^:=chr(48+(cardinal(value) and 1));
- value:=qword(value) shr 1;
- dec(p);
- end;
- digits:=p-p2+1;
- if digits>0 then
- fillchar(result[1],digits,#48);
- end;
- function FindPart(const HelpWilds, InputStr: string): SizeInt;
- var
- i, J, NWilds: SizeInt;
- begin
- if Pos('?',HelpWilds)=0 then
- Exit(Pos(HelpWilds, inputStr));
- NWilds:=Length(HelpWilds);
- for i:=0 to Length(inputStr) - NWilds do
- begin
- J:=1;
- while (J<=NWilds) and ((inputStr[i + J] = HelpWilds[J]) or (HelpWilds[J] = '?')) do
- Inc(J);
- if J>NWilds then
- Exit(i+1);
- end;
- Result:=0;
- end;
- function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
- var
- Wp,We,Ip,Ie,WpBack,IpBack: PChar;
- begin
- if ignoreCase then { upcase all letters }
- begin
- inputStr:=AnsiUpperCase(inputStr);
- Wilds:=AnsiUpperCase(Wilds);
- end;
- Wp:=PChar(Pointer(Wilds));
- We:=Wp+Length(Wilds);
- Ip:=PChar(Pointer(InputStr));
- Ie:=Ip+Length(InputStr);
- WpBack:=nil;
- while Ip<Ie do
- begin
- if Wp<We then
- if (Wp^=Ip^) or (Wp^='?') then
- begin
- Inc(Ip);
- Inc(Wp);
- continue;
- end
- else if Wp^='*' then
- begin
- Inc(Wp);
- WpBack:=Wp;
- IpBack:=Ip;
- continue;
- end;
- if not Assigned(WpBack) then
- exit(false);
- Wp:=WpBack;
- Inc(IpBack);
- Ip:=IpBack;
- end;
- while (Wp<We) and (Wp^='*') do
- Inc(Wp);
- Result:=Wp=We;
- end;
- function XorString(const Key, Src: ShortString): ShortString;
- var
- i: SizeInt;
- begin
- Result:=Src;
- if Length(Key) > 0 then
- for i:=1 to Length(Src) do
- Result[i]:=Chr(Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Ord(Src[i]));
- end;
- function XorEncode(const Key, Source: Ansistring): Ansistring;
- var
- i: Integer;
- C: Byte;
- begin
- Result:='';
- for i:=1 to Length(Source) do
- begin
- if Length(Key) > 0 then
- C:=Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Byte(Source[i])
- else
- C:=Byte(Source[i]);
- Result:=Result+AnsiLowerCase(intToHex(C, 2));
- end;
- end;
- function XorDecode(const Key, Source: Ansistring): Ansistring;
- var
- i: Integer;
- C: AnsiChar;
- begin
- Result:='';
- for i:=0 to Length(Source) div 2 - 1 do
- begin
- C:=Chr(StrTointDef('$' + Copy(Source, (i * 2) + 1, 2), Ord(' ')));
- if Length(Key) > 0 then
- C:=Chr(Byte(Key[1 + (i mod Length(Key))]) xor Byte(C));
- Result:=Result + C;
- end;
- end;
- function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
- var
- i: Integer;
- S: string;
- begin
- i:=1;
- Result:='';
- while (Result='') and (i<=ParamCount) do
- begin
- S:=ParamStr(i);
- if (SwitchChars=[]) or ((S[1] in SwitchChars) and (Length(S) > 1)) and
- (AnsiCompareText(Copy(S,2,Length(S)-1),Switch)=0) then
- begin
- inc(i);
- if i<=ParamCount then
- Result:=ParamStr(i);
- end;
- inc(i);
- end;
- end;
- function RPosEx(C: AnsiChar; const S: AnsiString; offs: SizeInt): SizeInt;
- var p,p2: PAnsiChar;
- Begin
- If (offs>0) and (offs<=Length(S)) Then
- begin
- p:=@s[offs];
- p2:=@s[1];
- while (p2<=p) and (p^<>c) do dec(p);
- RPosEx:=(p-p2)+1;
- end
- else
- RPosEX:=0;
- End;
- function RPos(c: AnsiChar; const S: AnsiString): SizeInt;
- Begin
- Result:=RPosEx(c,S,Length(S)); { Length(S) must be used because character version returns 0 on offs > length. }
- End;
- function RPos(const Substr: AnsiString; const Source: AnsiString): SizeInt;
- begin
- Result:=RPosEx(Substr,Source,High(Result)); { High(Result) is possible because string version clamps offs > length to offs = length. }
- end;
- function RPosEx(const Substr: AnsiString; const Source: AnsiString; offs: SizeInt): SizeInt;
- var
- MaxLen,llen : SizeInt;
- c : AnsiChar;
- pc,pc2 : PAnsiChar;
- begin
- llen:=Length(SubStr);
- maxlen:=length(source);
- if offs<maxlen then maxlen:=offs;
- if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
- begin
- pc:=@source[maxlen-llen+1];
- pc2:=@source[1];
- c:=substr[1];
- repeat
- if (c=pc^) and
- (CompareChar(Substr[1],pc^,llen)=0) then
- begin
- rPosex:=pc-pc2+1;
- exit;
- end;
- dec(pc);
- until pc<pc2;
- end;
- rPosex:=0;
- end;
- function RPosEx(C: unicodechar; const S: UnicodeString; offs: SizeInt): SizeInt;
- var p,p2: PUnicodeChar;
- Begin
- If (offs>0) and (offs<=Length(S)) Then
- begin
- p:=@s[offs];
- p2:=@s[1];
- while (p2<=p) and (p^<>c) do dec(p);
- RPosEx:=SizeUint(pointer(p)-pointer(p2)) div sizeof(unicodechar)+1; { p-p2+1 but avoids signed division... }
- end
- else
- RPosEX:=0;
- End;
- function RPos(c: Unicodechar; const S: UnicodeString): SizeInt;
- Begin
- Result:=RPosEx(c,S,Length(S)); { Length(S) must be used because character version returns 0 on offs > length. }
- End;
- function RPos(const Substr: UnicodeString; const Source: UnicodeString): SizeInt;
- begin
- Result:=RPosEx(Substr,Source,High(Result)); { High(Result) is possible because string version clamps offs > length to offs = length. }
- end;
- function RPosEx(const Substr: UnicodeString; const Source: UnicodeString; offs: SizeInt): SizeInt;
- var
- MaxLen,llen : SizeInt;
- c : unicodechar;
- pc,pc2 : punicodechar;
- begin
- llen:=Length(SubStr);
- maxlen:=length(source);
- if offs<maxlen then maxlen:=offs;
- if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
- begin
- pc:=@source[maxlen-llen+1];
- pc2:=@source[1];
- c:=substr[1];
- repeat
- if (c=pc^) and
- (Compareword(Substr[1],pc^,llen)=0) then
- begin
- rPosex:=SizeUint(pointer(pc)-pointer(pc2)) div sizeof(unicodechar)+1; { pc-pc2+1 but avoids signed division... }
- exit;
- end;
- dec(pc);
- until pc<pc2;
- end;
- rPosex:=0;
- end;
- procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer);
- var
- i : longint;
- begin
- for i:=0 to BinBufSize-1 do
- begin
- HexValue[0]:=HexDigits[((Ord(BinValue[i]) shr 4))];
- HexValue[1]:=HexDigits[((Ord(BinValue[i]) and 15))];
- Inc(HexValue,2);
- end;
- end;
- procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer);
- var
- i : longint;
- begin
- for i:=0 to BinBufSize-1 do
- begin
- HexValue[0]:=HexDigitsW[((Ord(BinValue[i]) shr 4))];
- HexValue[1]:=HexDigitsW[((Ord(BinValue[i]) and 15))];
- Inc(HexValue,2);
- end;
- end;
- procedure BinToHex(const BinBuffer: TBytes; BinBufOffset: Integer; var HexBuffer: TBytes; HexBufOffset: Integer; Count: Integer);
- var
- i : longint;
- begin
- for i:=0 to Count-1 do
- begin
- HexBuffer[HexBufOffset+2*i+0]:=Byte(HexDigits[(BinBuffer[BinBufOffset + i] shr 4)]);
- HexBuffer[HexBufOffset+2*i+1]:=Byte(HexDigits[(BinBuffer[BinBufOffset + i] and 15)]);
- end;
- end;
- procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer);
- begin
- BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
- end;
- procedure BinToHex(BinValue: Pointer; HexValue: PWideChar; BinBufSize: Integer);
- begin
- BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
- end;
- procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer);
- begin
- BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
- end;
-
- procedure BinToHex(const BinValue; HexValue: PWideChar; BinBufSize: Integer);
- begin
- BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
- end;
- function HexToBin(const HexText: PWideChar; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer;
- var
- i : Integer;
- PText : PWideChar;
- PBinBuf : PAnsiChar;
- begin
- PText:=HexText+HexTextOffset;
- PBinBuf:=PAnsiChar(BinBuffer)+BinBufOffset;
- i:=Count;
- Result:=HexToBin(PText, PBinBuf, i);
- end;
- function HexToBin(const HexText: TBytes; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer;
- var
- i : Integer;
- PText : PAnsiChar;
- PBinBuf : PAnsiChar;
- begin
- PText:=PAnsiChar(HexText)+HexTextOffset;
- PBinBuf:=PAnsiChar(BinBuffer)+BinBufOffset;
- i:=Count;
- Result:=HexToBin(PText, PBinBuf, i);
- end;
- function HexToBin(HexText: PWideChar; BinBuffer: Pointer; BinBufSize: Integer): Integer;
- begin
- Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
- end;
- function HexToBin(const HexText: PWideChar; var BinBuffer; BinBufSize: Integer): Integer;
- begin
- Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
- end;
- function HexToBin(HexText: PAnsiChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer;
- var
- i,num : integer;
- begin
- i:=BinBufSize;
- while (i>0) do
- begin
- // get value of first character
- case HexText^ of
- '0'..'9':
- num:=ord(HexText^)-ord('0');
- 'a'..'f':
- num:=ord(HexText^)-(ord('a')-10);
- 'A'..'F':
- num:=ord(HexText^)-(ord('A')-10);
- else
- break;
- end;
- // add value of second character
- case HexText[1] of
- '0'..'9':
- num:=num shl 4 or (ord(HexText[1])-ord('0'));
- 'a'..'f':
- num:=num shl 4 or (ord(HexText[1])-(ord('a')-10));
- 'A'..'F':
- num:=num shl 4 or (ord(HexText[1])-(ord('A')-10));
- else
- break;
- end;
- BinBuffer^:=AnsiChar(num);
- inc(BinBuffer);
- inc(HexText,2);
- dec(i);
- end;
- Result:=BinBufSize-i;
- end;
- function HexToBin(HexText: PWideChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer;
- var
- i,num : integer;
- begin
- i:=BinBufSize;
- while (i>0) do
- begin
- // get value of first character
- case HexText^ of
- '0'..'9':
- num:=ord(HexText^)-ord('0');
- 'a'..'f':
- num:=ord(HexText^)-(ord('a')-10);
- 'A'..'F':
- num:=ord(HexText^)-(ord('A')-10);
- else // this includes >#255.
- break;
- end;
- // add value of second character
- case HexText[1] of
- '0'..'9':
- num:=num shl 4 or (ord(HexText[1])-ord('0'));
- 'a'..'f':
- num:=num shl 4 or (ord(HexText[1])-(ord('a')-10));
- 'A'..'F':
- num:=num shl 4 or (ord(HexText[1])-(ord('A')-10));
- else // this includes >#255.
- break;
- end;
- BinBuffer^:=AnsiChar(num);
- inc(BinBuffer);
- inc(HexText,2);
- dec(i);
- end;
- Result:=BinBufSize-i;
- end;
- function HexToBin(HexText: PAnsiChar; var BinBuffer; BinBufSize: Integer): Integer;
- begin
- Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
- end;
- function HexToBin(const HexText: PAnsiChar; BinBuffer: Pointer; BinBufSize: Integer): Integer;
- begin
- Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
- end;
- function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt;
- var i,j:SizeInt;
- begin
- i:=length(s);
- j:=count;
- while (j<=i) and (not (s[j] in c)) do inc(j);
- if (j>i) then
- j:=0; // not found.
- result:=j;
- end;
- function PosSet(const c: TSysCharSet; const s: ansistring): SizeInt;
- begin
- result:=possetex(c,s,1);
- end;
- function StringToCharset(const c: string): TSysCharSet;
- var
- i: SizeInt;
- begin
- result:=[];
- for i:=1 to length(c) do
- include(result,c[i]);
- end;
- function PosSetEx(const c: string; const s: ansistring; count: Integer): SizeInt;
- begin
- result:=0;
- if length(c)>0 then
- result:=possetex(StringToCharset(c),s,count);
- end;
- function PosSet(const c: string; const s: ansistring): SizeInt;
- begin
- result:=0;
- if length(c)>0 then
- result:=possetex(StringToCharset(c),s,1);
- end;
- procedure Removeleadingchars(VAR S: AnsiString; const CSet: TSysCharset);
- VAR I,J : Longint;
- Begin
- I:=Length(S);
- J:=1;
- While (J<=I) And (S[J] IN CSet) DO
- INC(J);
- IF J>1 Then
- Delete(S,1,J-1);
- End;
- procedure Removeleadingchars(VAR S: UnicodeString; const CSet: TSysCharset);
- VAR I,J : Longint;
- Begin
- I:=Length(S);
- J:=1;
- While (J<=I) And (S[J] IN CSet) DO
- INC(J);
- IF J>1 Then
- Delete(S,1,J-1);
- End;
- function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
- begin
- result:=s;
- removeleadingchars(result,cset);
- end;
- procedure RemoveTrailingChars(VAR S: AnsiString; const CSet: TSysCharset);
- VAR I,J: LONGINT;
- Begin
- I:=Length(S);
- J:=I;
- While (j>0) and (S[J] IN CSet) DO DEC(J);
- IF J<>I Then
- SetLength(S,J);
- End;
- procedure RemoveTrailingChars(VAR S: UnicodeString; const CSet: TSysCharset);
- VAR I,J: LONGINT;
- Begin
- I:=Length(S);
- J:=I;
- While (j>0) and (S[J] IN CSet) DO DEC(J);
- IF J<>I Then
- SetLength(S,J);
- End;
- function TrimRightSet(const S: String; const CSet: TSysCharSet): String;
- begin
- result:=s;
- RemoveTrailingchars(result,cset);
- end;
- procedure RemovePadChars(VAR S: AnsiString; const CSet: TSysCharset);
- VAR J,K: SizeInt;
- Begin
- J:=Length(S);
- While (j>0) and (S[J] IN CSet) DO DEC(J);
- k:=1;
- While (k<=J) And (S[k] IN CSet) DO
- INC(k);
- IF k>1 Then
- move(s[k],s[1],(j-k+1)*sizeof(S[1]));
- setlength(s,j-k+1);
- End;
- procedure RemovePadChars(VAR S: UnicodeString; const CSet: TSysCharset);
- VAR J,K: SizeInt;
- Begin
- J:=Length(S);
- While (j>0) and (S[J] IN CSet) DO DEC(J);
- k:=1;
- While (k<=J) And (S[k] IN CSet) DO
- INC(k);
- IF k>1 Then
- move(s[k],s[1],(j-k+1)*sizeof(S[1]));
- setlength(s,j-k+1);
- End;
- function TrimSet(const S: String;const CSet:TSysCharSet): String;
- begin
- result:=s;
- RemovePadChars(result,cset);
- end;
- Function SplitCommandLine(S : RawByteString) : TRawByteStringArray;
- Function GetNextWord : RawByteString;
- Const
- WhiteSpace = [' ',#9,#10,#13];
- Literals = ['"',''''];
- Var
- Wstart,wend : Integer;
- InLiteral : Boolean;
- LastLiteral : AnsiChar;
- Procedure AppendToResult;
- begin
- Result:=Result+Copy(S,WStart,WEnd-WStart);
- WStart:=Wend+1;
- end;
- begin
- Result:='';
- WStart:=1;
- While (WStart<=Length(S)) and charinset(S[WStart],WhiteSpace) do
- Inc(WStart);
- WEnd:=WStart;
- InLiteral:=False;
- LastLiteral:=#0;
- While (Wend<=Length(S)) and (Not charinset(S[Wend],WhiteSpace) or InLiteral) do
- begin
- if charinset(S[Wend],Literals) then
- If InLiteral then
- begin
- InLiteral:=Not (S[Wend]=LastLiteral);
- if not InLiteral then
- AppendToResult;
- end
- else
- begin
- InLiteral:=True;
- LastLiteral:=S[Wend];
- AppendToResult;
- end;
- inc(wend);
- end;
- AppendToResult;
- While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
- inc(Wend);
- Delete(S,1,WEnd-1);
- end;
- Var
- W : RawByteString;
- len : Integer;
- begin
- Len:=0;
- Result:=Default(TRawByteStringArray);
- SetLength(Result,(Length(S) div 2)+1);
- While Length(S)>0 do
- begin
- W:=GetNextWord;
- If (W<>'') then
- begin
- Result[Len]:=W;
- Inc(Len);
- end;
- end;
- SetLength(Result,Len);
- end;
- Function SplitCommandLine(S : UnicodeString) : TUnicodeStringArray;
- Function GetNextWord : UnicodeString;
- Const
- WhiteSpace = [' ',#9,#10,#13];
- Literals = ['"',''''];
- Var
- Wstart,wend : Integer;
- InLiteral : Boolean;
- LastLiteral : AnsiChar;
- Procedure AppendToResult;
- begin
- Result:=Result+Copy(S,WStart,WEnd-WStart);
- WStart:=Wend+1;
- end;
- begin
- Result:='';
- WStart:=1;
- While (WStart<=Length(S)) and charinset(S[WStart],WhiteSpace) do
- Inc(WStart);
- WEnd:=WStart;
- InLiteral:=False;
- LastLiteral:=#0;
- While (Wend<=Length(S)) and (Not charinset(S[Wend],WhiteSpace) or InLiteral) do
- begin
- if charinset(S[Wend],Literals) then
- If InLiteral then
- begin
- InLiteral:=Not (S[Wend]=LastLiteral);
- if not InLiteral then
- AppendToResult;
- end
- else
- begin
- InLiteral:=True;
- LastLiteral:=S[Wend];
- AppendToResult;
- end;
- inc(wend);
- end;
- AppendToResult;
- While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
- inc(Wend);
- Delete(S,1,WEnd-1);
- end;
- Var
- W : UnicodeString;
- len : Integer;
- begin
- Len:=0;
- Result:=Default(TUnicodeStringArray);
- SetLength(Result,(Length(S) div 2)+1);
- While Length(S)>0 do
- begin
- W:=GetNextWord;
- If (W<>'') then
- begin
- Result[Len]:=W;
- Inc(Len);
- end;
- end;
- SetLength(Result,Len);
- end;
- end.
|