strutils.pp 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407
  1. {
  2. Delphi/Kylix compatibility unit: String handling routines.
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2005 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. {$inline on}
  14. unit strutils;
  15. interface
  16. uses
  17. SysUtils{, Types};
  18. { ---------------------------------------------------------------------
  19. Case insensitive search/replace
  20. ---------------------------------------------------------------------}
  21. Function AnsiResemblesText(const AText, AOther: string): Boolean;
  22. Function AnsiContainsText(const AText, ASubText: string): Boolean;
  23. Function AnsiStartsText(const ASubText, AText: string): Boolean;
  24. Function AnsiEndsText(const ASubText, AText: string): Boolean;
  25. Function AnsiReplaceText(const AText, AFromText, AToText: string): string;inline;
  26. Function AnsiMatchText(const AText: string; const AValues: array of string): Boolean;inline;
  27. Function AnsiIndexText(const AText: string; const AValues: array of string): Integer;
  28. { ---------------------------------------------------------------------
  29. Case sensitive search/replace
  30. ---------------------------------------------------------------------}
  31. Function AnsiContainsStr(const AText, ASubText: string): Boolean;inline;
  32. Function AnsiStartsStr(const ASubText, AText: string): Boolean;
  33. Function AnsiEndsStr(const ASubText, AText: string): Boolean;
  34. Function AnsiReplaceStr(const AText, AFromText, AToText: string): string;inline;
  35. Function AnsiMatchStr(const AText: string; const AValues: array of string): Boolean;inline;
  36. Function AnsiIndexStr(const AText: string; const AValues: array of string): Integer;
  37. { ---------------------------------------------------------------------
  38. Miscellaneous
  39. ---------------------------------------------------------------------}
  40. Function DupeString(const AText: string; ACount: Integer): string;
  41. Function ReverseString(const AText: string): string;
  42. Function AnsiReverseString(const AText: AnsiString): AnsiString;inline;
  43. Function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
  44. Function RandomFrom(const AValues: array of string): string; overload;
  45. Function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string = ''): string; overload;
  46. function NaturalCompareText (const S1 , S2 : string ): Integer ;
  47. function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: Char): Integer;
  48. { ---------------------------------------------------------------------
  49. VB emulations.
  50. ---------------------------------------------------------------------}
  51. Function LeftStr(const AText: AnsiString; const ACount: Integer): AnsiString;inline;
  52. Function RightStr(const AText: AnsiString; const ACount: Integer): AnsiString;
  53. Function MidStr(const AText: AnsiString; const AStart, ACount: Integer): AnsiString;inline;
  54. Function RightBStr(const AText: AnsiString; const AByteCount: Integer): AnsiString;inline;
  55. Function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: Integer): AnsiString;inline;
  56. Function AnsiLeftStr(const AText: AnsiString; const ACount: Integer): AnsiString;inline;
  57. Function AnsiRightStr(const AText: AnsiString; const ACount: Integer): AnsiString;inline;
  58. Function AnsiMidStr(const AText: AnsiString; const AStart, ACount: Integer): AnsiString;inline;
  59. Function LeftBStr(const AText: AnsiString; const AByteCount: Integer): AnsiString;inline;
  60. Function LeftStr(const AText: WideString; const ACount: Integer): WideString;inline;
  61. Function RightStr(const AText: WideString; const ACount: Integer): WideString;
  62. Function MidStr(const AText: WideString; const AStart, ACount: Integer): WideString;inline;
  63. { ---------------------------------------------------------------------
  64. Extended search and replace
  65. ---------------------------------------------------------------------}
  66. const
  67. { Default word delimiters are any character except the core alphanumerics. }
  68. WordDelimiters: set of Char = [#0..#255] - ['a'..'z','A'..'Z','1'..'9','0'];
  69. resourcestring
  70. SErrAmountStrings = 'Amount of search and replace strings don''t match';
  71. type
  72. TStringSearchOption = (soDown, soMatchCase, soWholeWord);
  73. TStringSearchOptions = set of TStringSearchOption;
  74. TStringSeachOption = TStringSearchOption;
  75. Function SearchBuf(Buf: PChar; BufLen: Integer; SelStart, SelLength: Integer; SearchString: String; Options: TStringSearchOptions): PChar;
  76. Function SearchBuf(Buf: PChar; BufLen: Integer; SelStart, SelLength: Integer; SearchString: String): PChar;inline; // ; Options: TStringSearchOptions = [soDown]
  77. Function PosEx(const SubStr, S: string; Offset: Cardinal): Integer;
  78. Function PosEx(const SubStr, S: string): Integer;inline; // Offset: Cardinal = 1
  79. Function PosEx(c:char; const S: string; Offset: Cardinal): Integer;
  80. Function PosEx(const SubStr, S: UnicodeString; Offset: Cardinal): Integer;
  81. Function PosEx(c: WideChar; const S: UnicodeString; Offset: Cardinal): Integer;
  82. Function PosEx(const SubStr, S: UnicodeString): Integer;inline; // Offset: Cardinal = 1
  83. function StringsReplace(const S: string; OldPattern, NewPattern: array of string; Flags: TReplaceFlags): string;
  84. { ---------------------------------------------------------------------
  85. Delphi compat
  86. ---------------------------------------------------------------------}
  87. Function ReplaceStr(const AText, AFromText, AToText: string): string;inline;
  88. Function ReplaceText(const AText, AFromText, AToText: string): string;inline;
  89. { ---------------------------------------------------------------------
  90. Soundex Functions.
  91. ---------------------------------------------------------------------}
  92. type
  93. TSoundexLength = 1..MaxInt;
  94. Function Soundex(const AText: string; ALength: TSoundexLength): string;
  95. Function Soundex(const AText: string): string;inline; // ; ALength: TSoundexLength = 4
  96. type
  97. TSoundexIntLength = 1..8;
  98. Function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
  99. Function SoundexInt(const AText: string): Integer;inline; //; ALength: TSoundexIntLength = 4
  100. Function DecodeSoundexInt(AValue: Integer): string;
  101. Function SoundexWord(const AText: string): Word;
  102. Function DecodeSoundexWord(AValue: Word): string;
  103. Function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;inline;
  104. Function SoundexSimilar(const AText, AOther: string): Boolean;inline; //; ALength: TSoundexLength = 4
  105. Function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;inline;
  106. Function SoundexCompare(const AText, AOther: string): Integer;inline; //; ALength: TSoundexLength = 4
  107. Function SoundexProc(const AText, AOther: string): Boolean;
  108. type
  109. TCompareTextProc = Function(const AText, AOther: string): Boolean;
  110. Const
  111. AnsiResemblesProc: TCompareTextProc = @SoundexProc;
  112. { ---------------------------------------------------------------------
  113. Other functions, based on RxStrUtils.
  114. ---------------------------------------------------------------------}
  115. type
  116. TRomanConversionStrictness = (rcsStrict, rcsRelaxed, rcsDontCare);
  117. resourcestring
  118. SInvalidRomanNumeral = '%s is not a valid Roman numeral';
  119. function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
  120. function DelSpace(const S: string): string;
  121. function DelChars(const S: string; Chr: Char): string;
  122. function DelSpace1(const S: string): string;
  123. function Tab2Space(const S: string; Numb: Byte): string;
  124. function NPos(const C: string; S: string; N: Integer): Integer;
  125. Function RPosEX(C:char;const S : AnsiString;offs:cardinal):Integer; overload;
  126. Function RPosex (Const Substr : AnsiString; Const Source : AnsiString;offs:cardinal) : Integer; overload;
  127. Function RPos(c:char;const S : AnsiString):Integer; overload;
  128. Function RPos (Const Substr : AnsiString; Const Source : AnsiString) : Integer; overload;
  129. function AddChar(C: Char; const S: string; N: Integer): string;
  130. function AddCharR(C: Char; const S: string; N: Integer): string;
  131. function PadLeft(const S: string; N: Integer): string;inline;
  132. function PadRight(const S: string; N: Integer): string;inline;
  133. function PadCenter(const S: string; Len: Integer): string;
  134. function Copy2Symb(const S: string; Symb: Char): string;
  135. function Copy2SymbDel(var S: string; Symb: Char): string;
  136. function Copy2Space(const S: string): string;inline;
  137. function Copy2SpaceDel(var S: string): string;inline;
  138. function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
  139. function WordCount(const S: string; const WordDelims: TSysCharSet): Integer;
  140. function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): Integer;
  141. function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
  142. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; var Pos: Integer): string;
  143. function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
  144. function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
  145. function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
  146. function FindPart(const HelpWilds, InputStr: string): Integer;
  147. function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
  148. function XorString(const Key, Src: ShortString): ShortString;
  149. function XorEncode(const Key, Source: string): string;
  150. function XorDecode(const Key, Source: string): string;
  151. function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
  152. function Numb2USA(const S: string): string;
  153. function Hex2Dec(const S: string): Longint;
  154. function Dec2Numb(N: Longint; Len, Base: Byte): string;
  155. function Numb2Dec(S: string; Base: Byte): Longint;
  156. function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
  157. function IntToBin(Value: Longint; Digits: Integer): string;
  158. function intToBin(Value: int64; Digits:integer): string;
  159. function IntToRoman(Value: Longint): string;
  160. function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
  161. function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  162. function RomanToIntDef(Const S : String; const ADefault: Longint = 0; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  163. procedure BinToHex(BinValue, HexValue: PChar; BinBufSize: Integer);
  164. function HexToBin(HexValue, BinValue: PChar; BinBufSize: Integer): Integer;
  165. const
  166. DigitChars = ['0'..'9'];
  167. Brackets = ['(',')','[',']','{','}'];
  168. StdWordDelims = [#0..' ',',','.',';','/','\',':','''','"','`'] + Brackets;
  169. StdSwitchChars = ['-','/'];
  170. function PosSet (const c:TSysCharSet;const s : ansistring ):Integer;
  171. function PosSet (const c:string;const s : ansistring ):Integer;
  172. function PosSetEx (const c:TSysCharSet;const s : ansistring;count:Integer ):Integer;
  173. function PosSetEx (const c:string;const s : ansistring;count:Integer ):Integer;
  174. Procedure Removeleadingchars(VAR S : AnsiString; Const CSet:TSysCharset);
  175. Procedure RemoveTrailingChars(VAR S : AnsiString;Const CSet:TSysCharset);
  176. Procedure RemovePadChars(VAR S : AnsiString;Const CSet:TSysCharset);
  177. function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
  178. Function TrimRightSet(const S: String;const CSet:TSysCharSet): String;
  179. function TrimSet(const S: String;const CSet:TSysCharSet): String;
  180. implementation
  181. { ---------------------------------------------------------------------
  182. Possibly Exception raising functions
  183. ---------------------------------------------------------------------}
  184. function Hex2Dec(const S: string): Longint;
  185. var
  186. HexStr: string;
  187. begin
  188. if Pos('$',S)=0 then
  189. HexStr:='$'+ S
  190. else
  191. HexStr:=S;
  192. Result:=StrToInt(HexStr);
  193. end;
  194. {
  195. We turn off implicit exceptions, since these routines are tested, and it
  196. saves 20% codesize (and some speed) and don't throw exceptions, except maybe
  197. heap related. If they don't, that is consider a bug.
  198. In the future, be wary with routines that use strtoint, floating point
  199. and/or format() derivatives. And check every divisor for 0.
  200. }
  201. {$IMPLICITEXCEPTIONS OFF}
  202. { ---------------------------------------------------------------------
  203. Case insensitive search/replace
  204. ---------------------------------------------------------------------}
  205. Function AnsiResemblesText(const AText, AOther: string): Boolean;
  206. begin
  207. if Assigned(AnsiResemblesProc) then
  208. Result:=AnsiResemblesProc(AText,AOther)
  209. else
  210. Result:=False;
  211. end;
  212. Function AnsiContainsText(const AText, ASubText: string): Boolean;
  213. begin
  214. AnsiContainsText:=AnsiPos(AnsiUppercase(ASubText),AnsiUppercase(AText))>0;
  215. end;
  216. Function AnsiStartsText(const ASubText, AText: string): Boolean;
  217. begin
  218. if (Length(AText) >= Length(ASubText)) and (ASubText <> '') then
  219. Result := AnsiStrLIComp(PChar(ASubText), PChar(AText), Length(ASubText)) = 0
  220. else
  221. Result := False;
  222. end;
  223. Function AnsiEndsText(const ASubText, AText: string): Boolean;
  224. begin
  225. if Length(AText) >= Length(ASubText) then
  226. Result := AnsiStrLIComp(PChar(ASubText),
  227. PChar(AText) + Length(AText) - Length(ASubText), Length(ASubText)) = 0
  228. else
  229. Result := False;
  230. end;
  231. Function AnsiReplaceText(const AText, AFromText, AToText: string): string;inline;
  232. begin
  233. Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll,rfIgnoreCase]);
  234. end;
  235. Function AnsiMatchText(const AText: string; const AValues: array of string): Boolean;
  236. begin
  237. Result:=(AnsiIndexText(AText,AValues)<>-1)
  238. end;
  239. Function AnsiIndexText(const AText: string; const AValues: array of string): Integer;
  240. var i : longint;
  241. begin
  242. result:=-1;
  243. if high(AValues)=-1 Then
  244. Exit;
  245. for i:=low(AValues) to High(Avalues) do
  246. if CompareText(avalues[i],atext)=0 Then
  247. exit(i); // make sure it is the first val.
  248. end;
  249. { ---------------------------------------------------------------------
  250. Case sensitive search/replace
  251. ---------------------------------------------------------------------}
  252. Function AnsiContainsStr(const AText, ASubText: string): Boolean;inline;
  253. begin
  254. Result := AnsiPos(ASubText,AText)>0;
  255. end;
  256. Function AnsiStartsStr(const ASubText, AText: string): Boolean;
  257. begin
  258. if (Length(AText) >= Length(ASubText)) and (ASubText <> '') then
  259. Result := AnsiStrLComp(PChar(ASubText), PChar(AText), Length(ASubText)) = 0
  260. else
  261. Result := False;
  262. end;
  263. Function AnsiEndsStr(const ASubText, AText: string): Boolean;
  264. begin
  265. if Length(AText) >= Length(ASubText) then
  266. Result := AnsiStrLComp(PChar(ASubText),
  267. PChar(AText) + Length(AText) - Length(ASubText), Length(ASubText)) = 0
  268. else
  269. Result := False;
  270. end;
  271. Function AnsiReplaceStr(const AText, AFromText, AToText: string): string;inline;
  272. begin
  273. Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll]);
  274. end;
  275. Function AnsiMatchStr(const AText: string; const AValues: array of string): Boolean;
  276. begin
  277. Result:=AnsiIndexStr(AText,Avalues)<>-1;
  278. end;
  279. Function AnsiIndexStr(const AText: string; const AValues: array of string): Integer;
  280. var
  281. i : longint;
  282. begin
  283. result:=-1;
  284. if high(AValues)=-1 Then
  285. Exit;
  286. for i:=low(AValues) to High(Avalues) do
  287. if (avalues[i]=AText) Then
  288. exit(i); // make sure it is the first val.
  289. end;
  290. { ---------------------------------------------------------------------
  291. Playthingies
  292. ---------------------------------------------------------------------}
  293. Function DupeString(const AText: string; ACount: Integer): string;
  294. var i,l : integer;
  295. begin
  296. result:='';
  297. if aCount>=0 then
  298. begin
  299. l:=length(atext);
  300. SetLength(result,aCount*l);
  301. for i:=0 to ACount-1 do
  302. move(atext[1],Result[l*i+1],l);
  303. end;
  304. end;
  305. Function ReverseString(const AText: string): string;
  306. var
  307. i,j:longint;
  308. begin
  309. setlength(result,length(atext));
  310. i:=1; j:=length(atext);
  311. while (i<=j) do
  312. begin
  313. result[i]:=atext[j-i+1];
  314. inc(i);
  315. end;
  316. end;
  317. Function AnsiReverseString(const AText: AnsiString): AnsiString;inline;
  318. begin
  319. Result:=ReverseString(AText);
  320. end;
  321. Function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
  322. var i,j,k : SizeUInt;
  323. begin
  324. j:=length(ASubText);
  325. i:=length(AText);
  326. if AStart>i then
  327. aStart:=i+1;
  328. k:=i+1-AStart;
  329. if ALength> k then
  330. ALength:=k;
  331. SetLength(Result,i+j-ALength);
  332. move (AText[1],result[1],AStart-1);
  333. move (ASubText[1],result[AStart],j);
  334. move (AText[AStart+ALength], Result[AStart+j],i+1-AStart-ALength);
  335. end;
  336. Function RandomFrom(const AValues: array of string): string; overload;
  337. begin
  338. if high(AValues)=-1 then exit('');
  339. result:=Avalues[random(High(AValues)+1)];
  340. end;
  341. Function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string = ''): string; overload;
  342. begin
  343. if avalue then
  344. result:=atrue
  345. else
  346. result:=afalse;
  347. end;
  348. function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: Char): Integer;
  349. {
  350. NaturalCompareBase compares strings in a collated order and
  351. so numbers are sorted too. It sorts like this:
  352. 01
  353. 001
  354. 0001
  355. and
  356. 0
  357. 00
  358. 000
  359. 000_A
  360. 000_B
  361. in a intuitive order.
  362. }
  363. var
  364. Num1, Num2: double;
  365. pStr1, pStr2: PChar;
  366. Len1, Len2: integer;
  367. TextLen1, TextLen2: integer;
  368. TextStr1: string = '';
  369. TextStr2: string = '';
  370. i: integer;
  371. j: integer;
  372. function Sign(const AValue: Integer): integer;inline;
  373. begin
  374. If Avalue<0 then
  375. Result:=-1
  376. else If Avalue>0 then
  377. Result:=1
  378. else
  379. Result:=0;
  380. end;
  381. function IsNumber(ch: char): boolean;
  382. begin
  383. Result := ch in ['0'..'9'];
  384. end;
  385. function GetInteger(var pch: PChar; var Len: integer): double;
  386. begin
  387. Result := 0;
  388. while (pch^ <> #0) and IsNumber(pch^) do
  389. begin
  390. Result := Result * 10 + Ord(pch^) - Ord('0');
  391. Inc(Len);
  392. Inc(pch);
  393. end;
  394. end;
  395. procedure GetChars;
  396. begin
  397. TextLen1 := 0;
  398. while not ((pStr1 + TextLen1)^ in ['0'..'9']) and ((pStr1 + TextLen1)^ <> #0) do
  399. Inc(TextLen1);
  400. SetLength(TextStr1, TextLen1);
  401. i := 1;
  402. j := 0;
  403. while i <= TextLen1 do
  404. begin
  405. TextStr1[i] := (pStr1 + j)^;
  406. Inc(i);
  407. Inc(j);
  408. end;
  409. TextLen2 := 0;
  410. while not ((pStr2 + TextLen2)^ in ['0'..'9']) and ((pStr2 + TextLen2)^ <> #0) do
  411. Inc(TextLen2);
  412. SetLength(TextStr2, TextLen2);
  413. i := 1;
  414. j := 0;
  415. while i <= TextLen2 do
  416. begin
  417. TextStr2[i] := (pStr2 + j)^;
  418. Inc(i);
  419. Inc(j);
  420. end;
  421. end;
  422. begin
  423. if (Str1 <> '') and (Str2 <> '') then
  424. begin
  425. pStr1 := PChar(Str1);
  426. pStr2 := PChar(Str2);
  427. Result := 0;
  428. while not ((pStr1^ = #0) or (pStr2^ = #0)) do
  429. begin
  430. TextLen1 := 1;
  431. TextLen2 := 1;
  432. Len1 := 0;
  433. Len2 := 0;
  434. while (pStr1^ = ' ') do
  435. begin
  436. Inc(pStr1);
  437. Inc(Len1);
  438. end;
  439. while (pStr2^ = ' ') do
  440. begin
  441. Inc(pStr2);
  442. Inc(Len2);
  443. end;
  444. if IsNumber(pStr1^) and IsNumber(pStr2^) then
  445. begin
  446. Num1 := GetInteger(pStr1, Len1);
  447. Num2 := GetInteger(pStr2, Len2);
  448. if Num1 < Num2 then
  449. Result := -1
  450. else if Num1 > Num2 then
  451. Result := 1
  452. else
  453. begin
  454. Result := Sign(Len1 - Len2);
  455. end;
  456. Dec(pStr1);
  457. Dec(pStr2);
  458. end
  459. else
  460. begin
  461. GetChars;
  462. if TextStr1 <> TextStr2 then
  463. Result := WideCompareText(UTF8Decode(TextStr1), UTF8Decode(TextStr2))
  464. else
  465. Result := 0;
  466. end;
  467. if Result <> 0 then
  468. Break;
  469. Inc(pStr1, TextLen1);
  470. Inc(pStr2, TextLen2);
  471. end;
  472. end;
  473. Num1 := Length(Str1);
  474. Num2 := Length(Str2);
  475. if (Result = 0) and (Num1 <> Num2) then
  476. begin
  477. if Num1 < Num2 then
  478. Result := -1
  479. else
  480. Result := 1;
  481. end;
  482. end;
  483. function NaturalCompareText (const S1 , S2 : string ): Integer ;
  484. begin
  485. Result := NaturalCompareText(S1, S2,
  486. DefaultFormatSettings.DecimalSeparator,
  487. DefaultFormatSettings.ThousandSeparator);
  488. end;
  489. { ---------------------------------------------------------------------
  490. VB emulations.
  491. ---------------------------------------------------------------------}
  492. Function LeftStr(const AText: AnsiString; const ACount: Integer): AnsiString;inline;
  493. begin
  494. Result:=Copy(AText,1,ACount);
  495. end;
  496. Function RightStr(const AText: AnsiString; const ACount: Integer): AnsiString;
  497. var j,l:integer;
  498. begin
  499. l:=length(atext);
  500. j:=ACount;
  501. if j>l then j:=l;
  502. Result:=Copy(AText,l-j+1,j);
  503. end;
  504. Function MidStr(const AText: AnsiString; const AStart, ACount: Integer): AnsiString;inline;
  505. begin
  506. if (ACount=0) or (AStart>length(atext)) then
  507. exit('');
  508. Result:=Copy(AText,AStart,ACount);
  509. end;
  510. Function LeftBStr(const AText: AnsiString; const AByteCount: Integer): AnsiString;inline;
  511. begin
  512. Result:=LeftStr(AText,AByteCount);
  513. end;
  514. Function RightBStr(const AText: AnsiString; const AByteCount: Integer): AnsiString;inline;
  515. begin
  516. Result:=RightStr(Atext,AByteCount);
  517. end;
  518. Function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: Integer): AnsiString;inline;
  519. begin
  520. Result:=MidStr(AText,AByteStart,AByteCount);
  521. end;
  522. Function AnsiLeftStr(const AText: AnsiString; const ACount: Integer): AnsiString;inline;
  523. begin
  524. Result := copy(AText,1,ACount);
  525. end;
  526. Function AnsiRightStr(const AText: AnsiString; const ACount: Integer): AnsiString;inline;
  527. begin
  528. Result := copy(AText,length(AText)-ACount+1,ACount);
  529. end;
  530. Function AnsiMidStr(const AText: AnsiString; const AStart, ACount: Integer): AnsiString;inline;
  531. begin
  532. Result:=Copy(AText,AStart,ACount);
  533. end;
  534. Function LeftStr(const AText: WideString; const ACount: Integer): WideString;inline;
  535. begin
  536. Result:=Copy(AText,1,ACount);
  537. end;
  538. Function RightStr(const AText: WideString; const ACount: Integer): WideString;
  539. var
  540. j,l:integer;
  541. begin
  542. l:=length(atext);
  543. j:=ACount;
  544. if j>l then j:=l;
  545. Result:=Copy(AText,l-j+1,j);
  546. end;
  547. Function MidStr(const AText: WideString; const AStart, ACount: Integer): WideString;inline;
  548. begin
  549. Result:=Copy(AText,AStart,ACount);
  550. end;
  551. { ---------------------------------------------------------------------
  552. Extended search and replace
  553. ---------------------------------------------------------------------}
  554. type
  555. TEqualFunction = function (const a,b : char) : boolean;
  556. function EqualWithCase (const a,b : char) : boolean;
  557. begin
  558. result := (a = b);
  559. end;
  560. function EqualWithoutCase (const a,b : char) : boolean;
  561. begin
  562. result := (lowerCase(a) = lowerCase(b));
  563. end;
  564. function IsWholeWord (bufstart, bufend, wordstart, wordend : pchar) : boolean;
  565. begin
  566. // Check start
  567. result := ((wordstart = bufstart) or ((wordstart-1)^ in worddelimiters)) and
  568. // Check end
  569. ((wordend = bufend) or ((wordend+1)^ in worddelimiters));
  570. end;
  571. function SearchDown(buf,aStart,endchar:pchar; SearchString:string;
  572. Equals : TEqualFunction; WholeWords:boolean) : pchar;
  573. var Found : boolean;
  574. s, c : pchar;
  575. begin
  576. result := aStart;
  577. Found := false;
  578. while not Found and (result <= endchar) do
  579. begin
  580. // Search first letter
  581. while (result <= endchar) and not Equals(result^,SearchString[1]) do
  582. inc (result);
  583. // Check if following is searchstring
  584. c := result;
  585. s := @(Searchstring[1]);
  586. Found := true;
  587. while (c <= endchar) and (s^ <> #0) and Found do
  588. begin
  589. Found := Equals(c^, s^);
  590. inc (c);
  591. inc (s);
  592. end;
  593. if s^ <> #0 then
  594. Found := false;
  595. // Check if it is a word
  596. if Found and WholeWords then
  597. Found := IsWholeWord(buf,endchar,result,c-1);
  598. if not found then
  599. inc (result);
  600. end;
  601. if not Found then
  602. result := nil;
  603. end;
  604. function SearchUp(buf,aStart,endchar:pchar; SearchString:string;
  605. equals : TEqualFunction; WholeWords:boolean) : pchar;
  606. var Found : boolean;
  607. s, c, l : pchar;
  608. begin
  609. result := aStart;
  610. Found := false;
  611. l := @(SearchString[length(SearchString)]);
  612. while not Found and (result >= buf) do
  613. begin
  614. // Search last letter
  615. while (result >= buf) and not Equals(result^,l^) do
  616. dec (result);
  617. // Check if before is searchstring
  618. c := result;
  619. s := l;
  620. Found := true;
  621. while (c >= buf) and (s >= @SearchString[1]) and Found do
  622. begin
  623. Found := Equals(c^, s^);
  624. dec (c);
  625. dec (s);
  626. end;
  627. if (s >= @(SearchString[1])) then
  628. Found := false;
  629. // Check if it is a word
  630. if Found and WholeWords then
  631. Found := IsWholeWord(buf,endchar,c+1,result);
  632. if found then
  633. result := c+1
  634. else
  635. dec (result);
  636. end;
  637. if not Found then
  638. result := nil;
  639. end;
  640. //function SearchDown(buf,aStart,endchar:pchar; SearchString:string; equal : TEqualFunction; WholeWords:boolean) : pchar;
  641. function SearchBuf(Buf: PChar;BufLen: Integer;SelStart: Integer;SelLength: Integer;
  642. SearchString: String;Options: TStringSearchOptions):PChar;
  643. var
  644. equal : TEqualFunction;
  645. begin
  646. SelStart := SelStart + SelLength;
  647. if (SearchString = '') or (SelStart > BufLen) or (SelStart < 0) then
  648. result := nil
  649. else
  650. begin
  651. if soMatchCase in Options then
  652. Equal := @EqualWithCase
  653. else
  654. Equal := @EqualWithoutCase;
  655. if soDown in Options then
  656. result := SearchDown(buf,buf+SelStart,Buf+(BufLen-1), SearchString, Equal, (soWholeWord in Options))
  657. else
  658. result := SearchUp(buf,buf+SelStart,Buf+(Buflen-1), SearchString, Equal, (soWholeWord in Options));
  659. end;
  660. end;
  661. Function SearchBuf(Buf: PChar; BufLen: Integer; SelStart, SelLength: Integer; SearchString: String): PChar;inline; // ; Options: TStringSearchOptions = [soDown]
  662. begin
  663. Result:=SearchBuf(Buf,BufLen,SelStart,SelLength,SearchString,[soDown]);
  664. end;
  665. Function PosEx(const SubStr, S: string; Offset: Cardinal): Integer;
  666. var
  667. i,MaxLen, SubLen : SizeInt;
  668. SubFirst: Char;
  669. pc : pchar;
  670. begin
  671. PosEx:=0;
  672. SubLen := Length(SubStr);
  673. if (SubLen > 0) and (Offset > 0) and (Offset <= Cardinal(Length(S))) then
  674. begin
  675. MaxLen := Length(S)- SubLen;
  676. SubFirst := SubStr[1];
  677. i := indexbyte(S[Offset],Length(S) - Offset + 1, Byte(SubFirst));
  678. while (i >= 0) and ((i + sizeint(Offset) - 1) <= MaxLen) do
  679. begin
  680. pc := @S[i+SizeInt(Offset)];
  681. //we know now that pc^ = SubFirst, because indexbyte returned a value > -1
  682. if (CompareByte(Substr[1],pc^,SubLen) = 0) then
  683. begin
  684. PosEx := i + SizeInt(Offset);
  685. Exit;
  686. end;
  687. //point Offset to next char in S
  688. Offset := sizeuint(i) + Offset + 1;
  689. i := indexbyte(S[Offset],Length(S) - Offset + 1, Byte(SubFirst));
  690. end;
  691. end;
  692. end;
  693. Function PosEx(c:char; const S: string; Offset: Cardinal): Integer;
  694. var
  695. Len : longint;
  696. p: SizeInt;
  697. begin
  698. Len := length(S);
  699. if (Offset < 1) or (Offset > SizeUInt(Length(S))) then exit(0);
  700. Len := length(S);
  701. p := indexbyte(S[Offset],Len-offset+1,Byte(c));
  702. if (p < 0) then
  703. PosEx := 0
  704. else
  705. PosEx := p + sizeint(Offset);
  706. end;
  707. Function PosEx(const SubStr, S: string): Integer;inline; // Offset: Cardinal = 1
  708. begin
  709. posex:=posex(substr,s,1);
  710. end;
  711. Function PosEx(const SubStr, S: UnicodeString; Offset: Cardinal): Integer;
  712. var
  713. i,MaxLen, SubLen : SizeInt;
  714. SubFirst: WideChar;
  715. pc : pwidechar;
  716. begin
  717. PosEx:=0;
  718. SubLen := Length(SubStr);
  719. if (SubLen > 0) and (Offset > 0) and (Offset <= Cardinal(Length(S))) then
  720. begin
  721. MaxLen := Length(S)- SubLen;
  722. SubFirst := SubStr[1];
  723. i := indexword(S[Offset],Length(S) - Offset + 1, Word(SubFirst));
  724. while (i >= 0) and ((i + sizeint(Offset) - 1) <= MaxLen) do
  725. begin
  726. pc := @S[i+SizeInt(Offset)];
  727. //we know now that pc^ = SubFirst, because indexbyte returned a value > -1
  728. if (CompareWord(Substr[1],pc^,SubLen) = 0) then
  729. begin
  730. PosEx := i + SizeInt(Offset);
  731. Exit;
  732. end;
  733. //point Offset to next char in S
  734. Offset := sizeuint(i) + Offset + 1;
  735. i := indexword(S[Offset],Length(S) - Offset + 1, Word(SubFirst));
  736. end;
  737. end;
  738. end;
  739. Function PosEx(c: WideChar; const S: UnicodeString; Offset: Cardinal): Integer;
  740. var
  741. Len : longint;
  742. p: SizeInt;
  743. begin
  744. Len := length(S);
  745. if (Offset < 1) or (Offset > SizeUInt(Length(S))) then exit(0);
  746. Len := length(S);
  747. p := indexword(S[Offset],Len-offset+1,Word(c));
  748. if (p < 0) then
  749. PosEx := 0
  750. else
  751. PosEx := p + sizeint(Offset);
  752. end;
  753. Function PosEx(const SubStr, S: UnicodeString): Integer;inline; // Offset: Cardinal = 1
  754. begin
  755. PosEx:=PosEx(SubStr,S,1);
  756. end;
  757. function StringsReplace(const S: string; OldPattern, NewPattern: array of string; Flags: TReplaceFlags): string;
  758. var pc,pcc,lastpc : pchar;
  759. strcount : integer;
  760. ResStr,
  761. CompStr : string;
  762. Found : Boolean;
  763. sc : integer;
  764. begin
  765. sc := length(OldPattern);
  766. if sc <> length(NewPattern) then
  767. raise exception.Create(SErrAmountStrings);
  768. dec(sc);
  769. if rfIgnoreCase in Flags then
  770. begin
  771. CompStr:=AnsiUpperCase(S);
  772. for strcount := 0 to sc do
  773. OldPattern[strcount] := AnsiUpperCase(OldPattern[strcount]);
  774. end
  775. else
  776. CompStr := s;
  777. ResStr := '';
  778. pc := @CompStr[1];
  779. pcc := @s[1];
  780. lastpc := pc+Length(S);
  781. while pc < lastpc do
  782. begin
  783. Found := False;
  784. for strcount := 0 to sc do
  785. begin
  786. if (length(OldPattern[strcount])>0) and
  787. (OldPattern[strcount][1]=pc^) and
  788. (Length(OldPattern[strcount]) <= (lastpc-pc)) and
  789. (CompareByte(OldPattern[strcount][1],pc^,Length(OldPattern[strcount]))=0) then
  790. begin
  791. ResStr := ResStr + NewPattern[strcount];
  792. pc := pc+Length(OldPattern[strcount]);
  793. pcc := pcc+Length(OldPattern[strcount]);
  794. Found := true;
  795. end
  796. end;
  797. if not found then
  798. begin
  799. ResStr := ResStr + pcc^;
  800. inc(pc);
  801. inc(pcc);
  802. end
  803. else if not (rfReplaceAll in Flags) then
  804. begin
  805. ResStr := ResStr + StrPas(pcc);
  806. break;
  807. end;
  808. end;
  809. Result := ResStr;
  810. end;
  811. { ---------------------------------------------------------------------
  812. Delphi compat
  813. ---------------------------------------------------------------------}
  814. Function ReplaceStr(const AText, AFromText, AToText: string): string;inline;
  815. begin
  816. result:=AnsiReplaceStr(AText, AFromText, AToText);
  817. end;
  818. Function ReplaceText(const AText, AFromText, AToText: string): string;inline;
  819. begin
  820. result:=AnsiReplaceText(AText, AFromText, AToText);
  821. end;
  822. { ---------------------------------------------------------------------
  823. Soundex Functions.
  824. ---------------------------------------------------------------------}
  825. Const
  826. SScore : array[1..255] of Char =
  827. ('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
  828. '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
  829. '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
  830. '0','0','0','0','0','0', // 91..96
  831. '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
  832. '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
  833. '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
  834. '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
  835. '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
  836. '0','0','0','0','0'); // 251..255
  837. Function Soundex(const AText: string; ALength: TSoundexLength): string;
  838. Var
  839. S,PS : Char;
  840. I,L : integer;
  841. begin
  842. Result:='';
  843. PS:=#0;
  844. If Length(AText)>0 then
  845. begin
  846. Result:=Upcase(AText[1]);
  847. I:=2;
  848. L:=Length(AText);
  849. While (I<=L) and (Length(Result)<ALength) do
  850. begin
  851. S:=SScore[Ord(AText[i])];
  852. If Not (S in ['0','i',PS]) then
  853. Result:=Result+S;
  854. If (S<>'i') then
  855. PS:=S;
  856. Inc(I);
  857. end;
  858. end;
  859. L:=Length(Result);
  860. If (L<ALength) then
  861. Result:=Result+StringOfChar('0',Alength-L);
  862. end;
  863. Function Soundex(const AText: string): string;inline; // ; ALength: TSoundexLength = 4
  864. begin
  865. Result:=Soundex(AText,4);
  866. end;
  867. Const
  868. Ord0 = Ord('0');
  869. OrdA = Ord('A');
  870. Function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
  871. var
  872. SE: string;
  873. I: Integer;
  874. begin
  875. Result:=-1;
  876. SE:=Soundex(AText,ALength);
  877. If Length(SE)>0 then
  878. begin
  879. Result:=Ord(SE[1])-OrdA;
  880. if ALength > 1 then
  881. begin
  882. Result:=Result*26+(Ord(SE[2])-Ord0);
  883. for I:=3 to ALength do
  884. Result:=(Ord(SE[I])-Ord0)+Result*7;
  885. end;
  886. Result:=ALength+Result*9;
  887. end;
  888. end;
  889. Function SoundexInt(const AText: string): Integer;inline; //; ALength: TSoundexIntLength = 4
  890. begin
  891. Result:=SoundexInt(AText,4);
  892. end;
  893. Function DecodeSoundexInt(AValue: Integer): string;
  894. var
  895. I, Len: Integer;
  896. begin
  897. Result := '';
  898. Len := AValue mod 9;
  899. AValue := AValue div 9;
  900. for I:=Len downto 3 do
  901. begin
  902. Result:=Chr(Ord0+(AValue mod 7))+Result;
  903. AValue:=AValue div 7;
  904. end;
  905. if Len>1 then
  906. begin
  907. Result:=Chr(Ord0+(AValue mod 26))+Result;
  908. AValue:=AValue div 26;
  909. end;
  910. Result:=Chr(OrdA+AValue)+Result;
  911. end;
  912. Function SoundexWord(const AText: string): Word;
  913. Var
  914. S : String;
  915. begin
  916. S:=SoundEx(Atext,4);
  917. Result:=Ord(S[1])-OrdA;
  918. Result:=Result*26+ord(S[2])-48;
  919. Result:=Result*7+ord(S[3])-48;
  920. Result:=Result*7+ord(S[4])-48;
  921. end;
  922. Function DecodeSoundexWord(AValue: Word): string;
  923. begin
  924. Result := Chr(Ord0+ (AValue mod 7));
  925. AValue := AValue div 7;
  926. Result := Chr(Ord0+ (AValue mod 7)) + Result;
  927. AValue := AValue div 7;
  928. Result := IntToStr(AValue mod 26) + Result;
  929. AValue := AValue div 26;
  930. Result := Chr(OrdA+AValue) + Result;
  931. end;
  932. Function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;inline;
  933. begin
  934. Result:=Soundex(AText,ALength)=Soundex(AOther,ALength);
  935. end;
  936. Function SoundexSimilar(const AText, AOther: string): Boolean;inline; //; ALength: TSoundexLength = 4
  937. begin
  938. Result:=SoundexSimilar(AText,AOther,4);
  939. end;
  940. Function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;inline;
  941. begin
  942. Result:=AnsiCompareStr(Soundex(AText,ALength),Soundex(AOther,ALength));
  943. end;
  944. Function SoundexCompare(const AText, AOther: string): Integer;inline; //; ALength: TSoundexLength = 4
  945. begin
  946. Result:=SoundexCompare(AText,AOther,4);
  947. end;
  948. Function SoundexProc(const AText, AOther: string): Boolean;
  949. begin
  950. Result:=SoundexSimilar(AText,AOther);
  951. end;
  952. { ---------------------------------------------------------------------
  953. RxStrUtils-like functions.
  954. ---------------------------------------------------------------------}
  955. function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
  956. var
  957. i,l: Integer;
  958. begin
  959. l:=Length(S);
  960. i:=1;
  961. Result:=True;
  962. while Result and (i<=l) do
  963. begin
  964. Result:=(S[i] in EmptyChars);
  965. Inc(i);
  966. end;
  967. end;
  968. function DelSpace(const S: String): string;
  969. begin
  970. Result:=DelChars(S,' ');
  971. end;
  972. function DelChars(const S: string; Chr: Char): string;
  973. var
  974. I,J: Integer;
  975. begin
  976. Result:=S;
  977. I:=Length(Result);
  978. While I>0 do
  979. begin
  980. if Result[I]=Chr then
  981. begin
  982. J:=I-1;
  983. While (J>0) and (Result[J]=Chr) do
  984. Dec(j);
  985. Delete(Result,J+1,I-J);
  986. I:=J+1;
  987. end;
  988. dec(I);
  989. end;
  990. end;
  991. function DelSpace1(const S: string): string;
  992. var
  993. i: Integer;
  994. begin
  995. Result:=S;
  996. for i:=Length(Result) downto 2 do
  997. if (Result[i]=' ') and (Result[I-1]=' ') then
  998. Delete(Result,I,1);
  999. end;
  1000. function Tab2Space(const S: string; Numb: Byte): string;
  1001. var
  1002. I: Integer;
  1003. begin
  1004. I:=1;
  1005. Result:=S;
  1006. while I <= Length(Result) do
  1007. if Result[I]<>Chr(9) then
  1008. inc(I)
  1009. else
  1010. begin
  1011. Result[I]:=' ';
  1012. If (Numb>1) then
  1013. Insert(StringOfChar(' ',Numb-1),Result,I);
  1014. Inc(I,Numb);
  1015. end;
  1016. end;
  1017. function NPos(const C: string; S: string; N: Integer): Integer;
  1018. var
  1019. i,p,k: Integer;
  1020. begin
  1021. Result:=0;
  1022. if N<1 then
  1023. Exit;
  1024. k:=0;
  1025. i:=1;
  1026. Repeat
  1027. p:=pos(C,S);
  1028. Inc(k,p);
  1029. if p>0 then
  1030. delete(S,1,p);
  1031. Inc(i);
  1032. Until (i>n) or (p=0);
  1033. If (P>0) then
  1034. Result:=K;
  1035. end;
  1036. function AddChar(C: Char; const S: string; N: Integer): string;
  1037. Var
  1038. l : Integer;
  1039. begin
  1040. Result:=S;
  1041. l:=Length(Result);
  1042. if l<N then
  1043. Result:=StringOfChar(C,N-l)+Result;
  1044. end;
  1045. function AddCharR(C: Char; const S: string; N: Integer): string;
  1046. Var
  1047. l : Integer;
  1048. begin
  1049. Result:=S;
  1050. l:=Length(Result);
  1051. if l<N then
  1052. Result:=Result+StringOfChar(C,N-l);
  1053. end;
  1054. function PadRight(const S: string; N: Integer): string;inline;
  1055. begin
  1056. Result:=AddCharR(' ',S,N);
  1057. end;
  1058. function PadLeft(const S: string; N: Integer): string;inline;
  1059. begin
  1060. Result:=AddChar(' ',S,N);
  1061. end;
  1062. function Copy2Symb(const S: string; Symb: Char): string;
  1063. var
  1064. p: Integer;
  1065. begin
  1066. p:=Pos(Symb,S);
  1067. if p=0 then
  1068. p:=Length(S)+1;
  1069. Result:=Copy(S,1,p-1);
  1070. end;
  1071. function Copy2SymbDel(var S: string; Symb: Char): string;
  1072. var
  1073. p: Integer;
  1074. begin
  1075. p:=Pos(Symb,S);
  1076. if p=0 then
  1077. begin
  1078. result:=s;
  1079. s:='';
  1080. end
  1081. else
  1082. begin
  1083. Result:=Copy(S,1,p-1);
  1084. delete(s,1,p);
  1085. end;
  1086. end;
  1087. function Copy2Space(const S: string): string;inline;
  1088. begin
  1089. Result:=Copy2Symb(S,' ');
  1090. end;
  1091. function Copy2SpaceDel(var S: string): string;inline;
  1092. begin
  1093. Result:=Copy2SymbDel(S,' ');
  1094. end;
  1095. function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
  1096. var
  1097. // l : Integer;
  1098. P,PE : PChar;
  1099. begin
  1100. Result:=AnsiLowerCase(S);
  1101. P:=PChar(pointer(Result));
  1102. PE:=P+Length(Result);
  1103. while (P<PE) do
  1104. begin
  1105. while (P<PE) and (P^ in WordDelims) do
  1106. inc(P);
  1107. if (P<PE) then
  1108. P^:=UpCase(P^);
  1109. while (P<PE) and not (P^ in WordDelims) do
  1110. inc(P);
  1111. end;
  1112. end;
  1113. function WordCount(const S: string; const WordDelims: TSysCharSet): Integer;
  1114. var
  1115. P,PE : PChar;
  1116. begin
  1117. Result:=0;
  1118. P:=Pchar(pointer(S));
  1119. PE:=P+Length(S);
  1120. while (P<PE) do
  1121. begin
  1122. while (P<PE) and (P^ in WordDelims) do
  1123. Inc(P);
  1124. if (P<PE) then
  1125. inc(Result);
  1126. while (P<PE) and not (P^ in WordDelims) do
  1127. inc(P);
  1128. end;
  1129. end;
  1130. function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): Integer;
  1131. var
  1132. PS,P,PE : PChar;
  1133. Count: Integer;
  1134. begin
  1135. Result:=0;
  1136. Count:=0;
  1137. PS:=PChar(pointer(S));
  1138. PE:=PS+Length(S);
  1139. P:=PS;
  1140. while (P<PE) and (Count<>N) do
  1141. begin
  1142. while (P<PE) and (P^ in WordDelims) do
  1143. inc(P);
  1144. if (P<PE) then
  1145. inc(Count);
  1146. if (Count<>N) then
  1147. while (P<PE) and not (P^ in WordDelims) do
  1148. inc(P)
  1149. else
  1150. Result:=(P-PS)+1;
  1151. end;
  1152. end;
  1153. function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
  1154. var
  1155. i: Integer;
  1156. begin
  1157. Result:=ExtractWordPos(N,S,WordDelims,i);
  1158. end;
  1159. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; var Pos: Integer): string;
  1160. var
  1161. i,j,l: Integer;
  1162. begin
  1163. j:=0;
  1164. i:=WordPosition(N, S, WordDelims);
  1165. Pos:=i;
  1166. if (i<>0) then
  1167. begin
  1168. j:=i;
  1169. l:=Length(S);
  1170. while (j<=L) and not (S[j] in WordDelims) do
  1171. inc(j);
  1172. end;
  1173. SetLength(Result,j-i);
  1174. If ((j-i)>0) then
  1175. Move(S[i],Result[1],j-i);
  1176. end;
  1177. function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
  1178. var
  1179. w,i,l,len: Integer;
  1180. begin
  1181. w:=0;
  1182. i:=1;
  1183. l:=0;
  1184. len:=Length(S);
  1185. SetLength(Result, 0);
  1186. while (i<=len) and (w<>N) do
  1187. begin
  1188. if s[i] in Delims then
  1189. inc(w)
  1190. else
  1191. begin
  1192. if (N-1)=w then
  1193. begin
  1194. inc(l);
  1195. SetLength(Result,l);
  1196. Result[L]:=S[i];
  1197. end;
  1198. end;
  1199. inc(i);
  1200. end;
  1201. end;
  1202. function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
  1203. var
  1204. i,l: Integer;
  1205. begin
  1206. i:=Pos;
  1207. l:=Length(S);
  1208. while (i<=l) and not (S[i] in Delims) do
  1209. inc(i);
  1210. Result:=Copy(S,Pos,i-Pos);
  1211. while (i<=l) and (S[i] in Delims) do
  1212. inc(i);
  1213. Pos:=i;
  1214. end;
  1215. function isWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
  1216. var
  1217. i,Count : Integer;
  1218. begin
  1219. Result:=False;
  1220. Count:=WordCount(S, WordDelims);
  1221. I:=1;
  1222. While (Not Result) and (I<=Count) do
  1223. begin
  1224. Result:=ExtractWord(i,S,WordDelims)=W;
  1225. Inc(i);
  1226. end;
  1227. end;
  1228. function Numb2USA(const S: string): string;
  1229. var
  1230. i, NA: Integer;
  1231. begin
  1232. i:=Length(S);
  1233. Result:=S;
  1234. NA:=0;
  1235. while (i > 0) do begin
  1236. if ((Length(Result) - i + 1 - NA) mod 3 = 0) and (i <> 1) then
  1237. begin
  1238. insert(',', Result, i);
  1239. inc(NA);
  1240. end;
  1241. Dec(i);
  1242. end;
  1243. end;
  1244. function PadCenter(const S: string; Len: Integer): string;
  1245. begin
  1246. if Length(S)<Len then
  1247. begin
  1248. Result:=StringOfChar(' ',(Len div 2) -(Length(S) div 2))+S;
  1249. Result:=Result+StringOfChar(' ',Len-Length(Result));
  1250. end
  1251. else
  1252. Result:=S;
  1253. end;
  1254. function Dec2Numb(N: Longint; Len, Base: Byte): string;
  1255. var
  1256. C: Integer;
  1257. Number: Longint;
  1258. begin
  1259. if N=0 then
  1260. Result:='0'
  1261. else
  1262. begin
  1263. Number:=N;
  1264. Result:='';
  1265. while Number>0 do
  1266. begin
  1267. C:=Number mod Base;
  1268. if C>9 then
  1269. C:=C+55
  1270. else
  1271. C:=C+48;
  1272. Result:=Chr(C)+Result;
  1273. Number:=Number div Base;
  1274. end;
  1275. end;
  1276. if (Result<>'') then
  1277. Result:=AddChar('0',Result,Len);
  1278. end;
  1279. function Numb2Dec(S: string; Base: Byte): Longint;
  1280. var
  1281. i, P: Longint;
  1282. begin
  1283. i:=Length(S);
  1284. Result:=0;
  1285. S:=UpperCase(S);
  1286. P:=1;
  1287. while (i>=1) do
  1288. begin
  1289. if (S[i]>'@') then
  1290. Result:=Result+(Ord(S[i])-55)*P
  1291. else
  1292. Result:=Result+(Ord(S[i])-48)*P;
  1293. Dec(i);
  1294. P:=P*Base;
  1295. end;
  1296. end;
  1297. function RomanToIntDontCare(const S: String): Longint;
  1298. {This was the original implementation of RomanToInt,
  1299. it is internally used in TryRomanToInt when Strictness = rcsDontCare}
  1300. const
  1301. RomanChars = ['C','D','I','L','M','V','X'];
  1302. RomanValues : array['C'..'X'] of Word
  1303. = (100,500,0,0,0,0,1,0,0,50,1000,0,0,0,0,0,0,0,0,5,0,10);
  1304. var
  1305. index, Next: Char;
  1306. i,l: Integer;
  1307. Negative: Boolean;
  1308. begin
  1309. Result:=0;
  1310. i:=0;
  1311. Negative:=(Length(S)>0) and (S[1]='-');
  1312. if Negative then
  1313. inc(i);
  1314. l:=Length(S);
  1315. while (i<l) do
  1316. begin
  1317. inc(i);
  1318. index:=UpCase(S[i]);
  1319. if index in RomanChars then
  1320. begin
  1321. if Succ(i)<=l then
  1322. Next:=UpCase(S[i+1])
  1323. else
  1324. Next:=#0;
  1325. if (Next in RomanChars) and (RomanValues[index]<RomanValues[Next]) then
  1326. begin
  1327. inc(Result, RomanValues[Next]);
  1328. Dec(Result, RomanValues[index]);
  1329. inc(i);
  1330. end
  1331. else
  1332. inc(Result, RomanValues[index]);
  1333. end
  1334. else
  1335. begin
  1336. Result:=0;
  1337. Exit;
  1338. end;
  1339. end;
  1340. if Negative then
  1341. Result:=-Result;
  1342. end;
  1343. { TryRomanToInt: try to convert a roman numeral to an integer
  1344. Parameters:
  1345. S: Roman numeral (like: 'MCMXXII')
  1346. N: Integer value of S (only meaningfull if the function succeeds)
  1347. Stricness: controls how strict the parsing of S is
  1348. - rcsStrict:
  1349. * Follow common subtraction rules
  1350. - only 1 preceding subtraction character allowed: IX = 9, but IIX <> 8
  1351. - from M you can only subtract C
  1352. - from D you can only subtract C
  1353. - from C you can only subtract X
  1354. - from L you can only subtract X
  1355. - from X you can only subtract I
  1356. - from V you can only subtract I
  1357. * The numeral is parsed in "groups" (first M's, then D's etc.), the next group to be parsed
  1358. must always be of a lower denomination than the previous one.
  1359. Example: 'MMDCCXX' is allowed but 'MMCCXXDD' is not
  1360. * There can only ever be 3 consecutive M's, C's, X's or I's
  1361. * There can only ever be 1 D, 1 L and 1 V
  1362. * After IX or IV there can be no more characters
  1363. * Negative numbers are not supported
  1364. // As a consequence the maximum allowed Roman numeral is MMMCMXCIX = 3999, also N can never become 0 (zero)
  1365. - rcsRelaxed: Like rcsStrict but with the following exceptions:
  1366. * An infinite number of (leading) M's is allowed
  1367. * Up to 4 consecutive M's, C's, X's and I's are allowed
  1368. // So this is allowed: 'MMMMMMCXIIII' = 6124
  1369. - rcsDontCare:
  1370. * no checking on the order of "groups" is done
  1371. * there are no restrictions on the number of consecutive chars
  1372. * negative numbers are supported
  1373. * an empty string as input will return True and N will be 0
  1374. * invalid input will return false
  1375. // for backwards comatibility: it supports rather ludicrous input like '-IIIMIII' -> -(2+(1000-1)+3)=-1004
  1376. }
  1377. function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
  1378. var
  1379. i, Len: Integer;
  1380. Terminated: Boolean;
  1381. begin
  1382. Result := (False);
  1383. S := UpperCase(S); //don't use AnsiUpperCase please
  1384. Len := Length(S);
  1385. if (Strictness = rcsDontCare) then
  1386. begin
  1387. N := RomanToIntDontCare(S);
  1388. if (N = 0) then
  1389. begin
  1390. Result := (Len = 0);
  1391. end
  1392. else
  1393. Result := True;
  1394. Exit;
  1395. end;
  1396. if (Len = 0) then Exit;
  1397. i := 1;
  1398. N := 0;
  1399. Terminated := False;
  1400. //leading M's
  1401. while (i <= Len) and ((Strictness <> rcsStrict) or (i < 4)) and (S[i] = 'M') do
  1402. begin
  1403. //writeln('TryRomanToInt: Found 1000');
  1404. Inc(i);
  1405. N := N + 1000;
  1406. end;
  1407. //then CM or or CD or D or (C, CC, CCC, CCCC)
  1408. if (i <= Len) and (S[i] = 'D') then
  1409. begin
  1410. //writeln('TryRomanToInt: Found 500');
  1411. Inc(i);
  1412. N := N + 500;
  1413. end
  1414. else if (i + 1 <= Len) and (S[i] = 'C') then
  1415. begin
  1416. if (S[i+1] = 'M') then
  1417. begin
  1418. //writeln('TryRomanToInt: Found 900');
  1419. Inc(i,2);
  1420. N := N + 900;
  1421. end
  1422. else if (S[i+1] = 'D') then
  1423. begin
  1424. //writeln('TryRomanToInt: Found 400');
  1425. Inc(i,2);
  1426. N := N + 400;
  1427. end;
  1428. end ;
  1429. //next max 4 or 3 C's, depending on Strictness
  1430. if (i <= Len) and (S[i] = 'C') then
  1431. begin
  1432. //find max 4 C's
  1433. //writeln('TryRomanToInt: Found 100');
  1434. Inc(i);
  1435. N := N + 100;
  1436. if (i <= Len) and (S[i] = 'C') then
  1437. begin
  1438. //writeln('TryRomanToInt: Found 100');
  1439. Inc(i);
  1440. N := N + 100;
  1441. end;
  1442. if (i <= Len) and (S[i] = 'C') then
  1443. begin
  1444. //writeln('TryRomanToInt: Found 100');
  1445. Inc(i);
  1446. N := N + 100;
  1447. end;
  1448. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'C') then
  1449. begin
  1450. //writeln('TryRomanToInt: Found 100');
  1451. Inc(i);
  1452. N := N + 100;
  1453. end;
  1454. end;
  1455. //then XC or XL
  1456. if (i + 1 <= Len) and (S[i] = 'X') then
  1457. begin
  1458. if (S[i+1] = 'C') then
  1459. begin
  1460. //writeln('TryRomanToInt: Found 90');
  1461. Inc(i,2);
  1462. N := N + 90;
  1463. end
  1464. else if (S[i+1] = 'L') then
  1465. begin
  1466. //writeln('TryRomanToInt: Found 40');
  1467. Inc(i,2);
  1468. N := N + 40;
  1469. end;
  1470. end;
  1471. //then L
  1472. if (i <= Len) and (S[i] = 'L') then
  1473. begin
  1474. //writeln('TryRomanToInt: Found 50');
  1475. Inc(i);
  1476. N := N + 50;
  1477. end;
  1478. //then (X, xx, xxx, xxxx)
  1479. if (i <= Len) and (S[i] = 'X') then
  1480. begin
  1481. //find max 3 or 4 X's, depending on Strictness
  1482. //writeln('TryRomanToInt: Found 10');
  1483. Inc(i);
  1484. N := N + 10;
  1485. if (i <= Len) and (S[i] = 'X') then
  1486. begin
  1487. //writeln('TryRomanToInt: Found 10');
  1488. Inc(i);
  1489. N := N + 10;
  1490. end;
  1491. if (i <= Len) and (S[i] = 'X') then
  1492. begin
  1493. //writeln('TryRomanToInt: Found 10');
  1494. Inc(i);
  1495. N := N + 10;
  1496. end;
  1497. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'X') then
  1498. begin
  1499. //writeln('TryRomanToInt: Found 10');
  1500. Inc(i);
  1501. N := N + 10;
  1502. end;
  1503. end;
  1504. //then IX or IV
  1505. if (i + 1 <= Len) and (S[i] = 'I') then
  1506. begin
  1507. if (S[i+1] = 'X') then
  1508. begin
  1509. Terminated := (True);
  1510. //writeln('TryRomanToInt: Found 9');
  1511. Inc(i,2);
  1512. N := N + 9;
  1513. end
  1514. else if (S[i+1] = 'V') then
  1515. begin
  1516. Terminated := (True);
  1517. //writeln('TryRomanToInt: Found 4');
  1518. Inc(i,2);
  1519. N := N + 4;
  1520. end;
  1521. end;
  1522. //then V
  1523. if (not Terminated) and (i <= Len) and (S[i] = 'V') then
  1524. begin
  1525. //writeln('TryRomanToInt: Found 5');
  1526. Inc(i);
  1527. N := N + 5;
  1528. end;
  1529. //then I
  1530. if (not Terminated) and (i <= Len) and (S[i] = 'I') then
  1531. begin
  1532. Terminated := (True);
  1533. //writeln('TryRomanToInt: Found 1');
  1534. Inc(i);
  1535. N := N + 1;
  1536. //Find max 2 or 3 closing I's, depending on strictness
  1537. if (i <= Len) and (S[i] = 'I') then
  1538. begin
  1539. //writeln('TryRomanToInt: Found 1');
  1540. Inc(i);
  1541. N := N + 1;
  1542. end;
  1543. if (i <= Len) and (S[i] = 'I') then
  1544. begin
  1545. //writeln('TryRomanToInt: Found 1');
  1546. Inc(i);
  1547. N := N + 1;
  1548. end;
  1549. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'I') then
  1550. begin
  1551. //writeln('TryRomanToInt: Found 1');
  1552. Inc(i);
  1553. N := N + 1;
  1554. end;
  1555. end;
  1556. //writeln('TryRomanToInt: Len = ',Len,' i = ',i);
  1557. Result := (i > Len);
  1558. //if Result then writeln('TryRomanToInt: N = ',N);
  1559. end;
  1560. function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  1561. begin
  1562. if not TryRomanToInt(S, Result, Strictness) then
  1563. raise EConvertError.CreateFmt(SInvalidRomanNumeral,[S]);
  1564. end;
  1565. function RomanToIntDef(const S: String; const ADefault: Longint;
  1566. Strictness: TRomanConversionStrictness): Longint;
  1567. begin
  1568. if not TryRomanToInt(S, Result, Strictness) then
  1569. Result := ADefault;
  1570. end;
  1571. function intToRoman(Value: Longint): string;
  1572. const
  1573. Arabics : Array[1..13] of Integer
  1574. = (1,4,5,9,10,40,50,90,100,400,500,900,1000);
  1575. Romans : Array[1..13] of String
  1576. = ('I','IV','V','IX','X','XL','L','XC','C','CD','D','CM','M');
  1577. var
  1578. i: Integer;
  1579. begin
  1580. Result:='';
  1581. for i:=13 downto 1 do
  1582. while (Value >= Arabics[i]) do
  1583. begin
  1584. Value:=Value-Arabics[i];
  1585. Result:=Result+Romans[i];
  1586. end;
  1587. end;
  1588. function intToBin(Value: Longint; Digits, Spaces: Integer): string;
  1589. var endpos : integer;
  1590. p,p2:pchar;
  1591. k: integer;
  1592. begin
  1593. Result:='';
  1594. if (Digits>32) then
  1595. Digits:=32;
  1596. if (spaces=0) then
  1597. begin
  1598. result:=inttobin(value,digits);
  1599. exit;
  1600. end;
  1601. endpos:=digits+ (digits-1) div spaces;
  1602. setlength(result,endpos);
  1603. p:=@result[endpos];
  1604. p2:=@result[1];
  1605. k:=spaces;
  1606. while (p>=p2) do
  1607. begin
  1608. if k=0 then
  1609. begin
  1610. p^:=' ';
  1611. dec(p);
  1612. k:=spaces;
  1613. end;
  1614. p^:=chr(48+(cardinal(value) and 1));
  1615. value:=cardinal(value) shr 1;
  1616. dec(p);
  1617. dec(k);
  1618. end;
  1619. end;
  1620. function intToBin(Value: Longint; Digits:integer): string;
  1621. var p,p2 : pchar;
  1622. begin
  1623. result:='';
  1624. if digits<=0 then exit;
  1625. setlength(result,digits);
  1626. p:=pchar(pointer(@result[digits]));
  1627. p2:=pchar(pointer(@result[1]));
  1628. // typecasts because we want to keep intto* delphi compat and take an integer
  1629. while (p>=p2) and (cardinal(value)>0) do
  1630. begin
  1631. p^:=chr(48+(cardinal(value) and 1));
  1632. value:=cardinal(value) shr 1;
  1633. dec(p);
  1634. end;
  1635. digits:=p-p2+1;
  1636. if digits>0 then
  1637. fillchar(result[1],digits,#48);
  1638. end;
  1639. function intToBin(Value: int64; Digits:integer): string;
  1640. var p,p2 : pchar;
  1641. begin
  1642. result:='';
  1643. if digits<=0 then exit;
  1644. setlength(result,digits);
  1645. p:=pchar(pointer(@result[digits]));
  1646. p2:=pchar(pointer(@result[1]));
  1647. // typecasts because we want to keep intto* delphi compat and take a signed val
  1648. // and avoid warnings
  1649. while (p>=p2) and (qword(value)>0) do
  1650. begin
  1651. p^:=chr(48+(cardinal(value) and 1));
  1652. value:=qword(value) shr 1;
  1653. dec(p);
  1654. end;
  1655. digits:=p-p2+1;
  1656. if digits>0 then
  1657. fillchar(result[1],digits,#48);
  1658. end;
  1659. function FindPart(const HelpWilds, inputStr: string): Integer;
  1660. var
  1661. i, J: Integer;
  1662. Diff: Integer;
  1663. begin
  1664. Result:=0;
  1665. i:=Pos('?',HelpWilds);
  1666. if (i=0) then
  1667. Result:=Pos(HelpWilds, inputStr)
  1668. else
  1669. begin
  1670. Diff:=Length(inputStr) - Length(HelpWilds);
  1671. for i:=0 to Diff do
  1672. begin
  1673. for J:=1 to Length(HelpWilds) do
  1674. if (inputStr[i + J] = HelpWilds[J]) or (HelpWilds[J] = '?') then
  1675. begin
  1676. if (J=Length(HelpWilds)) then
  1677. begin
  1678. Result:=i+1;
  1679. Exit;
  1680. end;
  1681. end
  1682. else
  1683. Break;
  1684. end;
  1685. end;
  1686. end;
  1687. Function isMatch(inputstr,wilds : string; CWild, CinputWord: integer;MaxInputword,maxwilds : word) : Boolean;
  1688. begin
  1689. Result:=True;
  1690. repeat
  1691. if Wilds[CWild] = '*' then { handling of '*' }
  1692. begin
  1693. inc(CWild);
  1694. while Wilds[CWild] = '?' do { equal to '?' }
  1695. begin
  1696. { goto next letter }
  1697. inc(CWild);
  1698. inc(CinputWord);
  1699. end;
  1700. { increase until a match }
  1701. Repeat
  1702. while (inputStr[CinputWord]<>Wilds[CWild]) and (CinputWord <= MaxinputWord) do
  1703. inc(CinputWord);
  1704. Result:=isMatch(inputstr,wilds,CWild, CinputWord,MaxInputword,maxwilds);
  1705. if not Result then
  1706. Inc(cInputWord);
  1707. Until Result or (CinputWord>=MaxinputWord);
  1708. Continue;
  1709. end;
  1710. if Wilds[CWild] = '?' then { equal to '?' }
  1711. begin
  1712. { goto next letter }
  1713. inc(CWild);
  1714. inc(CinputWord);
  1715. Continue;
  1716. end;
  1717. if inputStr[CinputWord] = Wilds[CWild] then { equal letters }
  1718. begin
  1719. { goto next letter }
  1720. inc(CWild);
  1721. inc(CinputWord);
  1722. Continue;
  1723. end;
  1724. Result:=false;
  1725. Exit;
  1726. until (CinputWord > MaxinputWord) or (CWild > MaxWilds);
  1727. { no completed evaluation }
  1728. if (CinputWord <= MaxinputWord) or (CWild <= MaxWilds) then
  1729. Result:=false;
  1730. end;
  1731. function isWild(inputStr, Wilds: string; ignoreCase: boolean): boolean;
  1732. var
  1733. i: integer;
  1734. MaxinputWord, MaxWilds: integer; { Length of inputStr and Wilds }
  1735. begin
  1736. Result:=true;
  1737. if Wilds = inputStr then
  1738. Exit;
  1739. { delete '**', because '**' = '*' }
  1740. i:=Pos('**', Wilds);
  1741. while i > 0 do
  1742. begin
  1743. Delete(Wilds, i, 1);
  1744. i:=Pos('**', Wilds);
  1745. end;
  1746. if Wilds = '*' then { for fast end, if Wilds only '*' }
  1747. Exit;
  1748. MaxinputWord:=Length(inputStr);
  1749. MaxWilds:=Length(Wilds);
  1750. if (MaxWilds = 0) or (MaxinputWord = 0) then
  1751. begin
  1752. Result:=false;
  1753. Exit;
  1754. end;
  1755. if ignoreCase then { upcase all letters }
  1756. begin
  1757. inputStr:=AnsiUpperCase(inputStr);
  1758. Wilds:=AnsiUpperCase(Wilds);
  1759. end;
  1760. Result:=isMatch(inputStr,wilds,1,1,MaxinputWord, MaxWilds);
  1761. end;
  1762. function XorString(const Key, Src: ShortString): ShortString;
  1763. var
  1764. i: Integer;
  1765. begin
  1766. Result:=Src;
  1767. if Length(Key) > 0 then
  1768. for i:=1 to Length(Src) do
  1769. Result[i]:=Chr(Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Ord(Src[i]));
  1770. end;
  1771. function XorEncode(const Key, Source: string): string;
  1772. var
  1773. i: Integer;
  1774. C: Byte;
  1775. begin
  1776. Result:='';
  1777. for i:=1 to Length(Source) do
  1778. begin
  1779. if Length(Key) > 0 then
  1780. C:=Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Byte(Source[i])
  1781. else
  1782. C:=Byte(Source[i]);
  1783. Result:=Result+AnsiLowerCase(intToHex(C, 2));
  1784. end;
  1785. end;
  1786. function XorDecode(const Key, Source: string): string;
  1787. var
  1788. i: Integer;
  1789. C: Char;
  1790. begin
  1791. Result:='';
  1792. for i:=0 to Length(Source) div 2 - 1 do
  1793. begin
  1794. C:=Chr(StrTointDef('$' + Copy(Source, (i * 2) + 1, 2), Ord(' ')));
  1795. if Length(Key) > 0 then
  1796. C:=Chr(Byte(Key[1 + (i mod Length(Key))]) xor Byte(C));
  1797. Result:=Result + C;
  1798. end;
  1799. end;
  1800. function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
  1801. var
  1802. i: Integer;
  1803. S: string;
  1804. begin
  1805. i:=1;
  1806. Result:='';
  1807. while (Result='') and (i<=ParamCount) do
  1808. begin
  1809. S:=ParamStr(i);
  1810. if (SwitchChars=[]) or ((S[1] in SwitchChars) and (Length(S) > 1)) and
  1811. (AnsiCompareText(Copy(S,2,Length(S)-1),Switch)=0) then
  1812. begin
  1813. inc(i);
  1814. if i<=ParamCount then
  1815. Result:=ParamStr(i);
  1816. end;
  1817. inc(i);
  1818. end;
  1819. end;
  1820. Function RPosEX(C:char;const S : AnsiString;offs:cardinal):Integer; overload;
  1821. var I : SizeUInt;
  1822. p,p2: pChar;
  1823. Begin
  1824. I:=Length(S);
  1825. If (I<>0) and (offs<=i) Then
  1826. begin
  1827. p:=@s[offs];
  1828. p2:=@s[1];
  1829. while (p2<=p) and (p^<>c) do dec(p);
  1830. RPosEx:=(p-p2)+1;
  1831. end
  1832. else
  1833. RPosEX:=0;
  1834. End;
  1835. Function RPos(c:char;const S : AnsiString):Integer; overload;
  1836. var I : Integer;
  1837. p,p2: pChar;
  1838. Begin
  1839. I:=Length(S);
  1840. If I<>0 Then
  1841. begin
  1842. p:=@s[i];
  1843. p2:=@s[1];
  1844. while (p2<=p) and (p^<>c) do dec(p);
  1845. i:=p-p2+1;
  1846. end;
  1847. RPos:=i;
  1848. End;
  1849. Function RPos (Const Substr : AnsiString; Const Source : AnsiString) : Integer; overload;
  1850. var
  1851. MaxLen,llen : Integer;
  1852. c : char;
  1853. pc,pc2 : pchar;
  1854. begin
  1855. rPos:=0;
  1856. llen:=Length(SubStr);
  1857. maxlen:=length(source);
  1858. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  1859. begin
  1860. // i:=maxlen;
  1861. pc:=@source[maxlen];
  1862. pc2:=@source[llen-1];
  1863. c:=substr[llen];
  1864. while pc>=pc2 do
  1865. begin
  1866. if (c=pc^) and
  1867. (CompareChar(Substr[1],pchar(pc-llen+1)^,Length(SubStr))=0) then
  1868. begin
  1869. rPos:=pchar(pc-llen+1)-pchar(@source[1])+1;
  1870. exit;
  1871. end;
  1872. dec(pc);
  1873. end;
  1874. end;
  1875. end;
  1876. Function RPosex (Const Substr : AnsiString; Const Source : AnsiString;offs:cardinal) : Integer; overload;
  1877. var
  1878. MaxLen,llen : Integer;
  1879. c : char;
  1880. pc,pc2 : pchar;
  1881. begin
  1882. rPosex:=0;
  1883. llen:=Length(SubStr);
  1884. maxlen:=length(source);
  1885. if SizeInt(offs)<maxlen then maxlen:=offs;
  1886. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  1887. begin
  1888. // i:=maxlen;
  1889. pc:=@source[maxlen];
  1890. pc2:=@source[llen-1];
  1891. c:=substr[llen];
  1892. while pc>=pc2 do
  1893. begin
  1894. if (c=pc^) and
  1895. (CompareChar(Substr[1],pchar(pc-llen+1)^,Length(SubStr))=0) then
  1896. begin
  1897. rPosex:=pchar(pc-llen+1)-pchar(@source[1])+1;
  1898. exit;
  1899. end;
  1900. dec(pc);
  1901. end;
  1902. end;
  1903. end;
  1904. // def from delphi.about.com:
  1905. procedure BinToHex(BinValue, HexValue: PChar; BinBufSize: Integer);
  1906. Const
  1907. HexDigits='0123456789ABCDEF';
  1908. var
  1909. i : longint;
  1910. begin
  1911. for i:=0 to binbufsize-1 do
  1912. begin
  1913. HexValue[0]:=hexdigits[1+((ord(binvalue^) shr 4))];
  1914. HexValue[1]:=hexdigits[1+((ord(binvalue^) and 15))];
  1915. inc(hexvalue,2);
  1916. inc(binvalue);
  1917. end;
  1918. end;
  1919. function HexToBin(HexValue, BinValue: PChar; BinBufSize: Integer): Integer;
  1920. // more complex, have to accept more than bintohex
  1921. // A..F    1000001
  1922. // a..f    1100001
  1923. // 0..9     110000
  1924. var i,j,h,l : integer;
  1925. begin
  1926. i:=binbufsize;
  1927. while (i>0) do
  1928. begin
  1929. if hexvalue^ IN ['A'..'F','a'..'f'] then
  1930. h:=((ord(hexvalue^)+9) and 15)
  1931. else if hexvalue^ IN ['0'..'9'] then
  1932. h:=((ord(hexvalue^)) and 15)
  1933. else
  1934. break;
  1935. inc(hexvalue);
  1936. if hexvalue^ IN ['A'..'F','a'..'f'] then
  1937. l:=(ord(hexvalue^)+9) and 15
  1938. else if hexvalue^ IN ['0'..'9'] then
  1939. l:=(ord(hexvalue^)) and 15
  1940. else
  1941. break;
  1942. j := l + (h shl 4);
  1943. inc(hexvalue);
  1944. binvalue^:=chr(j);
  1945. inc(binvalue);
  1946. dec(i);
  1947. end;
  1948. result:=binbufsize-i;
  1949. end;
  1950. function possetex (const c:TSysCharSet;const s : ansistring;count:Integer ):Integer;
  1951. var i,j:Integer;
  1952. begin
  1953. if pchar(pointer(s))=nil then
  1954. j:=0
  1955. else
  1956. begin
  1957. i:=length(s);
  1958. j:=count;
  1959. if j>i then
  1960. begin
  1961. result:=0;
  1962. exit;
  1963. end;
  1964. while (j<=i) and (not (s[j] in c)) do inc(j);
  1965. if (j>i) then
  1966. j:=0; // not found.
  1967. end;
  1968. result:=j;
  1969. end;
  1970. function posset (const c:TSysCharSet;const s : ansistring ):Integer;
  1971. begin
  1972. result:=possetex(c,s,1);
  1973. end;
  1974. function possetex (const c:string;const s : ansistring;count:Integer ):Integer;
  1975. var cset : TSysCharSet;
  1976. i : integer;
  1977. begin
  1978. cset:=[];
  1979. if length(c)>0 then
  1980. for i:=1 to length(c) do
  1981. include(cset,c[i]);
  1982. result:=possetex(cset,s,count);
  1983. end;
  1984. function posset (const c:string;const s : ansistring ):Integer;
  1985. var cset : TSysCharSet;
  1986. i : integer;
  1987. begin
  1988. cset:=[];
  1989. if length(c)>0 then
  1990. for i:=1 to length(c) do
  1991. include(cset,c[i]);
  1992. result:=possetex(cset,s,1);
  1993. end;
  1994. Procedure Removeleadingchars(VAR S : AnsiString; Const CSet:TSysCharset);
  1995. VAR I,J : Longint;
  1996. Begin
  1997. I:=Length(S);
  1998. IF (I>0) Then
  1999. Begin
  2000. J:=1;
  2001. While (J<=I) And (S[J] IN CSet) DO
  2002. INC(J);
  2003. IF J>1 Then
  2004. Delete(S,1,J-1);
  2005. End;
  2006. End;
  2007. function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
  2008. begin
  2009. result:=s;
  2010. removeleadingchars(result,cset);
  2011. end;
  2012. Procedure RemoveTrailingChars(VAR S : AnsiString;Const CSet:TSysCharset);
  2013. VAR I,J: LONGINT;
  2014. Begin
  2015. I:=Length(S);
  2016. IF (I>0) Then
  2017. Begin
  2018. J:=I;
  2019. While (j>0) and (S[J] IN CSet) DO DEC(J);
  2020. IF J<>I Then
  2021. SetLength(S,J);
  2022. End;
  2023. End;
  2024. Function TrimRightSet(const S: String;const CSet:TSysCharSet): String;
  2025. begin
  2026. result:=s;
  2027. RemoveTrailingchars(result,cset);
  2028. end;
  2029. Procedure RemovePadChars(VAR S : AnsiString;Const CSet:TSysCharset);
  2030. VAR I,J,K: LONGINT;
  2031. Begin
  2032. I:=Length(S);
  2033. IF (I>0) Then
  2034. Begin
  2035. J:=I;
  2036. While (j>0) and (S[J] IN CSet) DO DEC(J);
  2037. if j=0 Then
  2038. begin
  2039. s:='';
  2040. exit;
  2041. end;
  2042. k:=1;
  2043. While (k<=I) And (S[k] IN CSet) DO
  2044. INC(k);
  2045. IF k>1 Then
  2046. begin
  2047. move(s[k],s[1],j-k+1);
  2048. setlength(s,j-k+1);
  2049. end
  2050. else
  2051. setlength(s,j);
  2052. End;
  2053. End;
  2054. function TrimSet(const S: String;const CSet:TSysCharSet): String;
  2055. begin
  2056. result:=s;
  2057. RemovePadChars(result,cset);
  2058. end;
  2059. end.