strutils.pas 50 KB

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