Is there a Delphi standard function for escaping HTML? - html

I've got a report that's supposed to take a grid control and produce HTML output. One of the columns in the grid can display any of a number of values, or <Any>. When this gets output to HTML, of course, it ends up blank.
I could probably write up some routine to use StringReplace to turn that into <Any> so it would display this particular case correctly, but I figure there's probably one in the RTL somewhere that's already been tested and does it right. Anyone know where I could find it?

I am 99 % sure that such a function does not exist in the RTL (as of Delphi 2009). Of course - however - it is trivial to write such a function.
Update
HTTPUtil.HTMLEscape is what you are looking for:
function HTMLEscape(const Str: string): string;
I don't dare to publish the code here (copyright violation, probably), but the routine is very simple. It encodes "<", ">", "&", and """ to <, >, &, and ". It also replaces characters #92, #160..#255 to decimal codes, e.g. \.
This latter step is unnecessary if the file is UTF-8, and also illogical, because higher special characters, such as ∮ are left as they are, while lower special characters, such as ×, are encoded.
Update 2
In response to the answer by Stijn Sanders, I made a simple performance test.
program Project1;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils;
var
t1, t2, t3, t4: Int64;
i: Integer;
str: string;
const
N = 100000;
function HTMLEncode(const Data: string): string;
var
i: Integer;
begin
result := '';
for i := 1 to length(Data) do
case Data[i] of
'<': result := result + '<';
'>': result := result + '>';
'&': result := result + '&';
'"': result := result + '"';
else
result := result + Data[i];
end;
end;
function HTMLEncode2(Data: string):string;
begin
Result:=
StringReplace(
StringReplace(
StringReplace(
StringReplace(
Data,
'&','&',[rfReplaceAll]),
'<','<',[rfReplaceAll]),
'>','>',[rfReplaceAll]),
'"','"',[rfReplaceAll]);
end;
begin
QueryPerformanceCounter(t1);
for i := 0 to N - 1 do
str := HTMLEncode('Testing. Is 3*4<3+4? Do you like "A & B"');
QueryPerformanceCounter(t2);
QueryPerformanceCounter(t3);
for i := 0 to N - 1 do
str := HTMLEncode2('Testing. Is 3*4<3+4? Do you like "A & B"');
QueryPerformanceCounter(t4);
Writeln(IntToStr(t2-t1));
Writeln(IntToStr(t4-t3));
Readln;
end.
The output is
532031
801969

It seems here is a small contest :) Here is a one more implementation:
function HTMLEncode3(const Data: string): string;
var
iPos, i: Integer;
procedure Encode(const AStr: String);
begin
Move(AStr[1], result[iPos], Length(AStr) * SizeOf(Char));
Inc(iPos, Length(AStr));
end;
begin
SetLength(result, Length(Data) * 6);
iPos := 1;
for i := 1 to length(Data) do
case Data[i] of
'<': Encode('<');
'>': Encode('>');
'&': Encode('&');
'"': Encode('"');
else
result[iPos] := Data[i];
Inc(iPos);
end;
SetLength(result, iPos - 1);
end;
Update 1: Updated initially provided incorrect code.
Update 2: And the times:
HTMLEncode : 2286508597
HTMLEncode2: 3577001647
HTMLEncode3: 361039770

I usually just use this code:
function HTMLEncode(Data:string):string;
begin
Result:=
StringReplace(
StringReplace(
StringReplace(
StringReplace(
StringReplace(
Data,
'&','&',[rfReplaceAll]),
'<','<',[rfReplaceAll]),
'>','>',[rfReplaceAll]),
'"','"',[rfReplaceAll]),
#13#10,'<br />'#13#10,[rfReplaceAll]);
end;
(copyright? it's open source)

Unit HTTPApp has a function called HTMLEncode. It has also other HTML/HTTP related functions.

I dont know in which delphi version it was introduced but, there is the System.NetEncoding unit which has:
TNetEncoding.HTML.Encode
TNetEncoding.HTML.Decode
functions. Read up here. You dont need external libraries anymore for that.

From unit Soap.HTTPUtil or simply HTTPUtil for older delphi versions, you can use
function HTMLEscape(const Str: string): string;
var
i: Integer;
begin
Result := '';
for i := Low(Str) to High(Str) do
begin
case Str[i] of
'<' : Result := Result + '<'; { Do not localize }
'>' : Result := Result + '>'; { Do not localize }
'&' : Result := Result + '&'; { Do not localize }
'"' : Result := Result + '"'; { Do not localize }
{$IFNDEF UNICODE}
#92, Char(160) .. #255 : Result := Result + '&#' + IntToStr(Ord(Str[ i ])) +';'; { Do not localize }
{$ELSE}
// NOTE: Not very efficient
#$0080..#$FFFF : Result := Result + '&#' + IntToStr(Ord(Str[ i ])) +';'; { Do not localize }
{$ENDIF}
else
Result := Result + Str[i];
end;
end;
end;

how about that way of replacing special characters:
function HtmlWeg(sS: String): String;
var
ix,cc: Integer;
sC, sR: String;
begin
result := sS;
ix := pos('\u00',sS);
while ix >0 do
begin
sc := copy(sS,ix+4,2) ;
cc := StrtoIntdef('$' +sC,32);
sR := '' + chr(cc);
sS := Stringreplace(sS, '\u00'+sC,sR,[rfreplaceall]) ;
ix := pos('\u00',sS);
end;
result := sS;
end;

My function combines the for-loop with a minimal reallocation of the string:
function HtmlEncode(const Value: string): string;
var
i: Integer;
begin
Result := Value;
i := 1;
while i <= Length(Result) do
begin
if Result[i] = '<' then
begin
Result[i] := '&';
Insert('lt;', Result, i + 1);
Inc(i, 4);
end
else if Result[i] = '>' then
begin
Result[i] := '&';
Insert('gt;', Result, i + 1);
Inc(i, 4);
end
else if Result[i] = '"' then
begin
Result[i] := '&';
Insert('quot;', Result, i + 1);
Inc(i, 6);
end
else if Result[i] = '&' then
begin
Insert('amp;', Result, i + 1);
Inc(i, 5);
end
else
Inc(i);
end;
end;

in delphi You have the function
THTMLEncoding.HTML.Encode

Related

Variables automatically changes its value

I'm doing this question with Pascal (Google Kick Start 2020 Round A - Workout) and I ran into a problem that doesn't make any sense at all. Here is a part of my program:
var N,K,i,max,max1 : longint;
M : array [1..100000] of longint;
A : array [1..99999] of longint;
begin
readln(N,K);
for i := 1 to N do
read(M[i]);
for i := 1 to N-1 do A[i] := M[i+1]-M[i];
max := 0;
for i := 1 to N-1 do
if A[i] >= max then
begin
max := A[i];
max1 := i;
end;
writeln('max = ',max); writeln('max1 = ',max1);
readln; readln;
end.
So first I type in all the input data which are:
5 6 and
9
10
20
26
30.
When I run the program, the value of max is 10 and the value of max1 is 2.
But when I change the way max gets its value and totally did nothing with max1, the program becomes like this:
uses crt;
var N,K,i,max,max1 : longint;
M : array [1..100000] of longint;
A : array [1..99999] of longint;
begin
readln(N,K);
for i := 1 to N do
read(M[i]);
for i := 1 to N-1 do A[i] := M[i+1]-M[i];
max := 0;
for i := 1 to N-1 do
if A[i] >= max then
begin
max := i;
max1 := i;
end;
writeln('max = ',max); writeln('max1 = ',max1);
readln; readln;
end.
I run the program, and suddenly both the values of max and max1 are 4. How can this happen? Should I delete Pascal?? By the way if you can't install Pascal for some reasons then go to this link:https://www.onlinegdb.com/, select Pascal language and paste my program. Thanks for helping me!

Functions giving different result with same parameters

I use GMLib to work with Google maps and now I have come to a point where I am very confused.
I have the functions GetDistance and GetHeading to calculate the distance and compass direction between 2 markers on my map.
When I call them from my procedure GetHeadingDistance I get the result I expect (distance and direction is correct)- aSearchCallInfo is a class containing info that needs to be updated with the values.
Now I am trying to add a function that lets the user press the right mouse button on the map and the get info about that location.
But in this case I get very wrong results. As far as I can see of the results it uses GMMarker.Items[1].Position as source even when I know that it is GMMarker.Items[0].Position I send as parameter.
When I try to debug the functions by writing values to a textfile during calculation, I can see that it is the correct values it gets to work with at the correct position.
(GMMarker.Items[0].Position is the position of the user of the software)
Any ideas as what I could try to get this solved?
procedure TfrmQthMap.GMMapRightClick(Sender: TObject; LatLng: TLatLng; X, Y: Double);
var
MessageText: string;
LL: TLatLng;
Heading: double;
Distance: double;
Qra: string;
begin
if GMMarker.Count > 0 then
begin
LL := TLatLng.Create;
try
LL.Lat := LatLng.Lat;
LL.Lng := LatLng.Lng;
Heading := GetHeading(GMMarker.Items[0].Position, LL);
Distance := GetDistance(GMMarker.Items[0].Position, LL);
Qra := Maidenhead(LatLng.LngToStr, LatLng.LatToStr);
finally
FreeAndNil(LL);
end;
MessageText := 'Data for det sted du klikkede på: ' + sLineBreak + sLineBreak +
Format('Længdegrad: %s', [LatLng.LngToStr(Precision)]) + sLineBreak +
Format('Breddegrad: %s', [LatLng.LatToStr(Precision)]) + sLineBreak +
Format('Afstand: %6.1f km', [Distance]) + sLineBreak +
Format('Retning: %6.1f °', [Heading]) + sLineBreak +
Format('Lokator: %s', [Qra]);
ShowMessage(MessageText);
end;
end;
procedure TfrmQthMap.GetHeadingDistance(aSearchCallInfo: TCallInfo);
var
Heading: double;
Distance: double;
begin
if GMMarker.Count > 1 then
begin
Heading := GetHeading(GMMarker.Items[0].Position, GMMarker.Items[1].Position);
Distance := GetDistance(GMMarker.Items[0].Position, GMMarker.Items[1].Position);
barFooter.Panels[PanelDist].Text := Format('Afstand: %6.1f km', [Distance]);
barFooter.Panels[PanelDir].Text := Format('Retning: %6.1f°', [Heading]);
aSearchCallInfo.Distance := Format('%6.1f km', [Distance]);
aSearchCallInfo.Heading := Format('%6.1f °', [Heading]);
aSearchCallInfo.SaveToDatabase;
end;
end;
function TfrmQthMap.GetDistance(aOrigin, aDest: TLatLng): double;
var
Distance: double;
begin
Distance := TGeometry.ComputeDistanceBetween(GMMap, aOrigin, aDest);
Distance := Distance / 1000;
Result := Distance;
end;
function TfrmQthMap.GetHeading(aOrigin, aDest: TLatLng): double;
var
Heading: double;
begin
Heading := TGeometry.ComputeHeading(GMMap, aOrigin, aDest);
Heading := 180 + Heading;
Result := Heading;
end;

Convert JSON String to Lua Table?

I need to convert a Json String to a table data structure in Lua. I am using the following code.
local json = require "json"
local t = {
["name1"] = "value1",
["name2"] = { 1, false, true, 23.54, "a \021 string" },
name3 = json.null
}
local encode = json.encode (t)
print (encode) --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}
local decode = json.decode( encode )
But when I run the script, I get the following errors,
no field package.preload['json']
no file '/usr/local/share/lua/5.2/json.lua'
no file '/usr/local/share/lua/5.2/json/init.lua'
no file '/usr/local/lib/lua/5.2/json.lua'
no file '/usr/local/lib/lua/5.2/json/init.lua'
no file './json.lua'
no file '/usr/local/lib/lua/5.2/json.so'
no file '/usr/local/lib/lua/5.2/loadall.so'
no file './json.so'
So how to convert my json string to lua table?
maybe lua-cjsonis your friend:
install e.g. through luarocks:
$sudo luarocks install lua-cjson
then in lua:
local json = require('cjson')
local tab = json.decode(json_string)
json_string = json.encode(tab)
https://gist.github.com/tylerneylon/59f4bcf316be525b30ab
I found pure lua script file to parse json data (just one file).
local json = {}
-- Internal functions.
local function kind_of(obj)
if type(obj) ~= 'table' then return type(obj) end
local i = 1
for _ in pairs(obj) do
if obj[i] ~= nil then i = i + 1 else return 'table' end
end
if i == 1 then return 'table' else return 'array' end
end
local function escape_str(s)
local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'}
for i, c in ipairs(in_char) do
s = s:gsub(c, '\\' .. out_char[i])
end
return s
end
-- Returns pos, did_find; there are two cases:
-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true.
-- 2. Delimiter not found: pos = pos after leading space; did_find = false.
-- This throws an error if err_if_missing is true and the delim is not found.
local function skip_delim(str, pos, delim, err_if_missing)
pos = pos + #str:match('^%s*', pos)
if str:sub(pos, pos) ~= delim then
if err_if_missing then
error('Expected ' .. delim .. ' near position ' .. pos)
end
return pos, false
end
return pos + 1, true
end
-- Expects the given pos to be the first character after the opening quote.
-- Returns val, pos; the returned pos is after the closing quote character.
local function parse_str_val(str, pos, val)
val = val or ''
local early_end_error = 'End of input found while parsing string.'
if pos > #str then error(early_end_error) end
local c = str:sub(pos, pos)
if c == '"' then return val, pos + 1 end
if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
-- We must have a \ character.
local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
local nextc = str:sub(pos + 1, pos + 1)
if not nextc then error(early_end_error) end
return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
end
-- Returns val, pos; the returned pos is after the number's final character.
local function parse_num_val(str, pos)
local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
local val = tonumber(num_str)
if not val then error('Error parsing number at position ' .. pos .. '.') end
return val, pos + #num_str
end
-- Public values and functions.
function json.stringify(obj, as_key)
local s = {} -- We'll build the string as an array of strings to be concatenated.
local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise.
if kind == 'array' then
if as_key then error('Can\'t encode array as key.') end
s[#s + 1] = '['
for i, val in ipairs(obj) do
if i > 1 then s[#s + 1] = ', ' end
s[#s + 1] = json.stringify(val)
end
s[#s + 1] = ']'
elseif kind == 'table' then
if as_key then error('Can\'t encode table as key.') end
s[#s + 1] = '{'
for k, v in pairs(obj) do
if #s > 1 then s[#s + 1] = ', ' end
s[#s + 1] = json.stringify(k, true)
s[#s + 1] = ':'
s[#s + 1] = json.stringify(v)
end
s[#s + 1] = '}'
elseif kind == 'string' then
return '"' .. escape_str(obj) .. '"'
elseif kind == 'number' then
if as_key then return '"' .. tostring(obj) .. '"' end
return tostring(obj)
elseif kind == 'boolean' then
return tostring(obj)
elseif kind == 'nil' then
return 'null'
else
error('Unjsonifiable type: ' .. kind .. '.')
end
return table.concat(s)
end
json.null = {} -- This is a one-off table to represent the null value.
function json.parse(str, pos, end_delim)
pos = pos or 1
if pos > #str then error('Reached unexpected end of input.') end
local pos = pos + #str:match('^%s*', pos) -- Skip whitespace.
local first = str:sub(pos, pos)
if first == '{' then -- Parse an object.
local obj, key, delim_found = {}, true, true
pos = pos + 1
while true do
key, pos = json.parse(str, pos, '}')
if key == nil then return obj, pos end
if not delim_found then error('Comma missing between object items.') end
pos = skip_delim(str, pos, ':', true) -- true -> error if missing.
obj[key], pos = json.parse(str, pos)
pos, delim_found = skip_delim(str, pos, ',')
end
elseif first == '[' then -- Parse an array.
local arr, val, delim_found = {}, true, true
pos = pos + 1
while true do
val, pos = json.parse(str, pos, ']')
if val == nil then return arr, pos end
if not delim_found then error('Comma missing between array items.') end
arr[#arr + 1] = val
pos, delim_found = skip_delim(str, pos, ',')
end
elseif first == '"' then -- Parse a string.
return parse_str_val(str, pos + 1)
elseif first == '-' or first:match('%d') then -- Parse a number.
return parse_num_val(str, pos)
elseif first == end_delim then -- End of an object or array.
return nil, pos + 1
else -- Parse true, false, or null.
local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
for lit_str, lit_val in pairs(literals) do
local lit_end = pos + #lit_str - 1
if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
end
local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
error('Invalid json syntax starting at ' .. pos_info_str)
end
end
return json
You can use json-lua. A pure lua implementation of json. First install json-lua using Luarocks. luarocks install json-lua . Then Use this code :
local json = require "json"
local t = {
["name1"] = "value1",
["name2"] = { 1, false, true, 23.54, "a \021 string" },
name3 = json.null
}
local encode = json:encode (t)
print (encode) --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}
local decode = json:decode( encode )
Tested & Verified on win 7 64 bit with lua 5.1. lua-cjson is fine, but it is not a pure lua rock. So, it's installation will not be easier to you.

Disappearing SubDetail TObjectList when JSonToObject

this is my first question. Sorry my english.
I have a classes like this:
TSFis_S = class(TPersistent)
private
_SFis_MID : Integer;
public
property SFis_MID : Integer read _SFis_MID write _SFis_MID;
end;
TSFis_D = class(TPersistent)
private
_SFis_MID : Integer;
_SFis_S : TObjectList<TSFis_S>;
public
property SFis_MID : Integer read _SFis_MID write _SFis_MID;
property SFis_S : TObjectList<TSFis_S> read _SFis_S write _SFis_S;
end;
TSFis_M = class(TPersistent)
private
_SFis_MID : Integer;
_SFis_D : TObjectList<TSFis_D>;
public
property SFis_MID : Integer read _SFis_MID write _SFis_MID;
property SFis_D : TObjectList<TSFis_D> read _SFis_D write _SFis_D;
function ToJSON:TJSONValue;
destructor Destroy;
end;
I trying convert TSFis_M Object to JSon and Revert to Object for my datasnap application. I use converts and reverters for my datatypes (TObjectList and TObjectList)
{ TSFis_M }
function JSonToSFis_M(json: TJSONValue): TSFis_M;
var
UnMarshaller: TJSONUnMarshal;
begin
if json is TJSONNull then
exit(nil);
UnMarshaller := TJSONUnMarshal.Create;
try
UnMarshaller.RegisterReverter(TSFis_M, '_FisTar',
procedure(Data: TObject; Field: string; Arg: string)
var
ctx: TRttiContext;
datetime :
TDateTime;
begin
datetime := EncodeDateTime(StrToInt(Copy(Arg, 7, 4)), StrToInt(Copy(Arg, 4, 2)), StrToInt(Copy(Arg, 1, 2)), StrToInt
(Copy(Arg, 12, 2)), StrToInt(Copy(Arg, 15, 2)), StrToInt(Copy(Arg, 18, 2)), 0);
ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
end
);
UnMarshaller.RegisterReverter(TSFis_D, '_SFis_S',
procedure(Data: TObject; Field: String; Args: TListOfObjects)
var
obj: TObject;
SFisS: TObjectList<TSFis_S>;
SFis, SFisNew: TSFis_S;
begin
if TSFis_D(Data)._SFis_S=Nil
then TSFis_D(Data)._SFis_S := TObjectList<TSFis_S>.Create(True);
SFisS := TSFis_D(Data)._SFis_S;
SFisS.Clear;
for obj in Args do
begin
SFis := obj as TSFis_S;
SFisNew := TSFis_S.Create;
SFisS.Add(SFisNew);
SFisNew._SFis_MID := SFis._SFis_MID;
end;
end
);
UnMarshaller.RegisterReverter(TSFis_M, '_SFis_D',
procedure(Data: TObject; Field: String; Args: TListOfObjects)
var
obj: TObject;
SFisD: TObjectList<TSFis_D>;
SFis, SFisNew: TSFis_D;
i: integer;
begin
if TSFis_M(Data)._SFis_D=Nil then
TSFis_M(Data)._SFis_D := TObjectList<TSFis_D>.Create(True);
SFisD := TSFis_M(Data)._SFis_D;
SFisD.Clear;
for obj in Args do
begin
SFis := obj as TSFis_D;
SFisNew := TSFis_D.Create;
SFisD.Add(SFisNew);
SFisNew._SFis_MID := SFis._SFis_MID;
end;
end
);
exit(Unmarshaller.Unmarshal(json) as TSFis_M)
finally
UnMarshaller.Free;
end;
end;
function TSFis_M.ToJSON: TJSONValue;
var
Marshaller: TJSONMarshal;
begin
if Assigned(Self) then
begin
Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
try
Marshaller.RegisterConverter(TSFis_M, '_SFis_D',
function(Data: TObject; Field: String): TListOfObjects
var
FisD: TObjectList<TSFis_D>;
i: integer;
begin
FisD := TSFis_M(Data)._SFis_D;
SetLength(Result, FisD.Count);
if FisD.Count > 0 then
for I := 0 to FisD.Count - 1 do
Result[I] := FisD[i];
end);
Marshaller.RegisterConverter(TSFis_M, '_FisTar',
function(Data: TObject; Field: string): string
var
ctx: TRttiContext; date : TDateTime;
begin
date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType<TDateTime>;
Result := FormatDateTime('dd.mm.yyyy hh:nn:ss', date);
end);
Marshaller.RegisterConverter(TSFis_D, '_SFis_S',
function(Data: TObject; Field: String): TListOfObjects
var
FisD: TObjectList<TSFis_S>;
i: integer;
begin
FisD := TSFis_D(Data)._SFis_S;
SetLength(Result, FisD.Count);
if FisD.Count > 0 then
for I := 0 to FisD.Count - 1 do
Result[I] := FisD[i];
end);
exit(Marshaller.Marshal(Self))
finally
Marshaller.Free;
end;
end
else
exit(TJSONNull.Create);
end;
And finally
for example i put 1 Button and 2 Memo on the form. And i try My created Object convert to Json, Json.ToString to Memo1. And Convert that JSonValue to Object.
procedure TForm1.Button1Click(Sender: TObject);
var
MainFis : TSFis_M;
MainFis2 : TSFis_M;
DFis : TSFis_D;
SFis : TSFis_S;
begin
MainFis := TSFis_M.Create;
MainFis.SFis_D := TObjectList<TSFis_D>.Create(True);
DFis := TSFis_D.Create;
DFis._SFis_MID := 1;
MainFis.SFis_D.Add(DFis);
SFis := TSFis_S.Create;
SFis._SFis_MID := 1;
DFis.SFis_S := TObjectList<TSFis_S>.Create(True);
DFis.SFis_S.Add(SFis);
Memo1.Text := MainFis.ToJSON.ToString;
Edit1.Text := IntToStr(MainFis.SFis_D[0].SFis_S.Count);
MainFis2 := JSonToSFis_M(MainFis.ToJSON);
Edit2.Text := IntToStr(MainFis2.SFis_D[0].SFis_S.Count); // Access violation. Because MainFis2.SFis_D[0].SFis_S = Nil Now (That's the my problem. Why?)
Memo2.Text := MainFis2.ToJSon.ToString;
end;
But when i do this. TSFis_S is disappearing. In first step (ObjectToJSon) no problem.
{"type":"Unit1.TSFis_M","id":1,"fields":
{"_SFis_MID":0,"_SFis_D":
[ {"type":"Unit1‌​.TSFis_D","id":2,"fields":
{"_SFis_MID":1,"_SFis_S":
[ {"type":"Unit1.TSFis_S","id":‌​3,"fields":{"_SFis_MID":1} } ]
}
} ]
}
}
But when i trying revert to Object reverter goes wrong.
I can't found problem. What's my fault.
Thanks
PS: If i didn't explain, sample code here: http://goo.gl/3QnSw

Traversing strings for multiple instances of substrings - freepascal or delphi

Platform : Lazarus 1.1, FreePascal 2.7.1, Win 7 32-bit.
I have a string value as follows:
FileName[12345][45678][6789].jpg
By default (assume this is default behaviour 0), my program currently pulls out the last set of numbers from the last pair of square brackets to the farthest right of the filename, i.e. 6789. It does so using this code:
if chkbxOverrideUniqueID.Checked then
IDOverrideValue := StrToInt(edtToggleValue.Text);
// User is happy to find the right most unique ID
if not chkbxOverrideUniqueID.Checked then
LastSquareBracket := RPos(']', strFileName);
PreceedingSquareBracket := RPosEx('[', strFileName, LastSquareBracket) + 1;
strFileID := AnsiMidStr(strFileName, PreceedingSquareBracket, LastSquareBracket - PreceedingSquareBracket)
else // User doesn't want to find the rightmost ID.
// and now I am stuck!
However, I have now added an option for the user to specify a non-default behaviour. e.g if they enter '1', that means "look for the first ID in from the farthest right ID". e.g. [45678], because [6789] is default behaviour 0, remember. If they enter 2, I want it to find [12345].
My question : How do I adapt the above code to achieve this, please?
The following code will return just the numeric value between brackets:
uses
StrUtils;
function GetNumber(const Text: string; Index: Integer): string;
var
I: Integer;
OpenPos: Integer;
ClosePos: Integer;
begin
Result := '';
ClosePos := Length(Text) + 1;
for I := 0 to Index do
begin
ClosePos := RPosEx(']', Text, ClosePos - 1);
if ClosePos = 0 then
Exit;
end;
OpenPos := RPosEx('[', Text, ClosePos - 1);
if OpenPos <> 0 then
Result := Copy(Text, OpenPos + 1, ClosePos - OpenPos - 1);
end;
If you'd like that value including those brackets, replace the last line with this:
Result := Copy(Text, OpenPos, ClosePos - OpenPos + 1);