strutils.pp 55 KB

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