strutils.pas 50 KB

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