parseutils.pas 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. unit parseutils;
  2. {$ifdef fpc}{$mode delphi}{$h+}{$endif}
  3. interface
  4. uses
  5. Classes, SysUtils;
  6. type
  7. TCharSet = set of Char;
  8. const
  9. EoLnChars = [#10,#13];
  10. SpaceChars = [#32,#9];
  11. InvsChars = [#0..#32];
  12. WhiteSpaceChars = SpaceChars;
  13. SpaceEolnChars = EoLnChars+SpaceChars;
  14. NumericChars = ['0'..'9'];
  15. HexChars = ['0'..'9','a'..'f','A'..'F'];
  16. SignChars = ['+','-'];
  17. SignNumericChars = NumericChars + SignChars;
  18. AlphabetChars = ['a'..'z','A'..'Z'];
  19. AlphaNumChars = AlphabetChars+NumericChars;
  20. function ScanWhile(const s: AnsiString; var index: Integer; const ch: TCharSet): AnsiString;
  21. function ScanTo(const s: AnsiString; var index: Integer; const ch: TCharSet): AnsiString;
  22. function SkipToEoln(const s: AnsiString; var index: Integer): AnsiString;
  23. function ScanToSubstr(const s: AnsiString; var index: Integer; const substr: string): AnsiString;
  24. // returns #10, #13, #10#13 or #13#10, if s[index] is end-of-line sequence
  25. // otherwise returns empty string
  26. function EolnStr(const s: AnsiString; index: Integer): String;
  27. function IsSubStr(const sbs, s: AnsiString; index: Integer): Boolean;
  28. // todo: not used?
  29. function SkipCommentBlock(const s: AnsiString; var index: Integer; const closecmt: AnsiString): AnsiString;
  30. function SkipLine(const s: AnsiString; var index: Integer): AnsiString;
  31. procedure OffsetToLinePos(const t: AnsiString; Offset: Integer; var P: TPoint);
  32. procedure ParseCSSValues(const s: String; css: TStrings);
  33. procedure GetCssAbsBoundsRect(Css: TStrings; var r: TRect);
  34. function CssValInt(const s: String; Def: integer): Integer;
  35. type
  36. TCNumberFormat = (nfError, nfInteger, nfHex, nfFloat);
  37. function ScanNumberC(const buf: string; var idx: Integer;
  38. var numberText: string): TCNumberFormat;
  39. implementation
  40. function CssValInt(const s: String; Def: integer): Integer;
  41. var
  42. i : integer;
  43. n : String;
  44. err : Integer;
  45. begin
  46. i:=1;
  47. n:=ScanWhile(s, i, ['+','-']+NumericChars);
  48. Val(n, Result, err);
  49. if err<>0 then Result:=Def;
  50. end;
  51. procedure GetCssAbsBoundsRect(Css: TStrings; var r: TRect);
  52. begin
  53. r.Left:=CssValInt(Css.Values['LEFT'], 0);
  54. r.Top:=CssValInt(Css.Values['top'], 0);
  55. r.Right:=r.Left+CssValInt(Css.Values['width'], 0);
  56. r.Bottom:=r.Top+CssValInt(Css.Values['height'], 0);
  57. end;
  58. procedure ParseCSSValues(const s: String; css: TStrings);
  59. var
  60. i : integer;
  61. n : String;
  62. v : String;
  63. begin
  64. i:=1;
  65. if (s='') or not Assigned(css) then Exit;
  66. while (i<=length(s)) do begin
  67. ScanTo(s, i, AlphaNumChars);
  68. n:=ScanWhile(s, i, AlphaNumChars+['_']);
  69. ScanTo(s, i, [':']);
  70. inc(i);
  71. ScanWhile(s, i, SpaceEolnChars);
  72. v:=ScanTo(s, i, [';']);
  73. css.Values[n]:=v;
  74. end;
  75. end;
  76. function ScanWhile(const s: AnsiString; var index: Integer; const ch: TCharSet): AnsiString;
  77. var
  78. i : Integer;
  79. begin
  80. Result := '';
  81. if (index <= 0) or (index > length(s)) then Exit;
  82. for i := index to length(s) do
  83. if not (s[i] in ch) then begin
  84. if i = index then Result := ''
  85. else Result := Copy(s, index, i - index);
  86. index := i;
  87. Exit;
  88. end;
  89. Result := Copy(s, index, length(s) - index + 1);
  90. index := length(s) + 1;
  91. end;
  92. function ScanTo(const s: AnsiString; var index: Integer; const ch: TCharSet): AnsiString;
  93. var
  94. i : Integer;
  95. begin
  96. Result := '';
  97. if (index <= 0) or (index > length(s)) then Exit;
  98. for i := index to length(s) do
  99. if (s[i] in ch) then begin
  100. if i = index then Result := ''
  101. else Result := Copy(s, index, i - index);
  102. index := i;
  103. Exit;
  104. end;
  105. Result := Copy(s, index, length(s) - index + 1);
  106. index := length(s) + 1;
  107. end;
  108. function EolnStr(const s: AnsiString; index: Integer): String;
  109. begin
  110. if (index<=0) or (index>length(s)) or (not (s[index] in EoLnChars)) then
  111. Result:=''
  112. else begin
  113. if (index<length(s)) and (s[index+1] in EolnChars) and (s[index]<>s[index+1]) then
  114. Result:=Copy(s, index, 2)
  115. else
  116. Result:=s[index];
  117. end;
  118. end;
  119. function SkipToEoln(const s: AnsiString; var index: Integer): AnsiString;
  120. begin
  121. Result := ScanTo(s, index, EoLnChars);
  122. end;
  123. function IsSubStr(const sbs, s: AnsiString; index: Integer): Boolean;
  124. var
  125. i : Integer;
  126. j : Integer;
  127. begin
  128. Result := false;
  129. if (sbs = '') or (length(sbs) > length(s) - index) then Exit;
  130. j := index;
  131. for i := 1 to length(sbs) do begin
  132. if sbs[i] <> s[j] then Exit;
  133. inc(j);
  134. end;
  135. Result := true;
  136. end;
  137. function SkipCommentBlock(const s: AnsiString; var index: Integer; const closecmt: AnsiString): AnsiString;
  138. begin
  139. Result := '';
  140. if closecmt = '' then begin
  141. index := length(s) + 1;
  142. Exit;
  143. end;
  144. while index <= length(s) do begin
  145. Result := Result + ScanTo(s, index, [closecmt[1]]+EoLnChars);
  146. //if (index<=length(s)) and (s in EoLnChars(
  147. if IsSubStr(closecmt, s, index) then begin
  148. inc(index, length(closecmt));
  149. Exit;
  150. end else begin
  151. Result := Result + s[index];
  152. inc(index);
  153. end;
  154. end;
  155. end;
  156. function SkipLine(const s: AnsiString; var index: Integer): AnsiString;
  157. begin
  158. Result:=ScanTo(s, index, EoLnChars);
  159. if (index<length(s)) and (s[index+1] in EoLnChars) and (s[index]<>s[index+1]) then
  160. inc(index);
  161. inc(index);
  162. end;
  163. procedure OffsetToLinePos(const t: AnsiString; Offset: Integer; var P: TPoint);
  164. var
  165. i, le : Integer;
  166. begin
  167. i := 1;
  168. le := 0;
  169. P.X := 0;
  170. P.Y := 0;
  171. while i < Offset do begin
  172. Inc(P.Y);
  173. le := i;
  174. SkipLine(t, i);
  175. end;
  176. P.X := Offset - le + 1;
  177. end;
  178. function isSubStrMatch(const s: AnsiString; index: integer; const substr: string): Boolean;
  179. var
  180. i : integer;
  181. j : integer;
  182. begin
  183. j:=index;
  184. Result:=false;
  185. for i:=1 to length(substr) do begin
  186. if s[j]<>substr[i] then Exit;
  187. inc(j);
  188. end;
  189. Result:=true;
  190. end;
  191. function ScanToSubstr(const s: AnsiString; var index: Integer; const substr: string): AnsiString;
  192. var
  193. i: integer;
  194. begin
  195. if substr='' then begin
  196. Result:='';
  197. Exit;
  198. end;
  199. i:=index;
  200. while (index<=length(s)) do begin
  201. ScanTo(s, index, [substr[1]]);
  202. if isSubStrMatch(s, index, substr) then begin
  203. inc(index, length(substr));
  204. Break;
  205. end else
  206. inc(index);
  207. end;
  208. Result:=Copy(s, i, index-i);
  209. end;
  210. function ScanNumberC(const buf: string; var idx: Integer; var numberText: string): TCNumberFormat;
  211. var
  212. ch : char;
  213. sec : string;
  214. begin
  215. Result := nfError;
  216. if buf[idx] in SignChars then begin
  217. ch:=buf[idx];
  218. inc(idx);
  219. end else
  220. ch := #0;
  221. if (idx<length(buf)) and (buf[idx]='0') and (buf[idx+1]='x') then begin
  222. inc(idx,2);
  223. numberText:='0x'+ScanWhile(buf, idx, HexChars);
  224. Result := nfHex;
  225. end else begin
  226. numberText:=ScanWhile(buf, idx, NumericChars);
  227. if ((idx<=length(buf)) and (buf[idx]='.')) then begin
  228. inc(idx);
  229. sec := ScanWhile(buf, idx, NumericChars);
  230. if (sec = '') then Exit;
  231. numberText:=NumberText+'.'+sec;
  232. Result := nfFloat;
  233. end else
  234. Result := nfInteger;
  235. end;
  236. if (ch<>#0) then begin
  237. if (numberText = '') then Exit;
  238. numberText:=ch+numberText;
  239. end;
  240. end;
  241. end.