Related
I attempted to port the BayerMoore algorithm for finding patterns in
strings using the TLA+ toolkit. My main question is about the
syntax. I think this error is thrown by these lines as the character to ASCII
conversion isn't automatic. This conversion is also required in the rest of
the code. How can I fix this ? Can I also ask if there is a way to execute
the code to test just once without simulating using the model checker ?
p := in_pattern[i];
flag[ p ] := 1;
I understand that the state space here is enormous. So I just simulate now but that doesn't seem to complete either.
: Attempted to apply function: ( 0 :> -1 ## 1 :> -1 ## 2 :> -1 ##
3 :> -1 ## 4 :> -1 ## ----- ----- to argument "T", which is not
in the domain of the function.
This is the pluscal code. It is written in an imperative style as I am still learning
TLA+
EXTENDS Integers, Sequences,Naturals, TLC
Max(x,y) == IF x < y THEN y ELSE x
(*--algorithm bayermoore
variables
i,m,l,n,j,k,p,skips,
flag \in [0 .. 256 -> -1 .. -1],
in_pattern = <<"T", "E", "S", "T">>,
in_text = <<"N", "T", "E", "S", "T", "E", "E", "D">>;
begin
i := 0;
while i < Len(in_pattern) do
i := i + 1;
p := in_pattern[i];
flag[ p ] := 1;
end while;
m := Len(in_pattern); n := Len(in_text); j := m - 1; k := n - m;
while j <= k do
skips := 0;
l := m - 1;
while j >= 0 do
if in_text[j] # in_text[i + j]
then
skips := Max(1,j - flag[in_text[i+j]]);
skip;
else
j := j - 1;
end if
end while;
if skips = 0
then
print i;
end if
end while;
end algorithm; *)
I believe the loops will work but that isn't fully tested.
The Java code that works is this.
public class BoyerMoore {
int R = 256;
String pattern = "TEST";
String text = "MYFUNNYONLINETESTCANSUCCEEDORNOT";
int[] right = new int[256];
public BoyerMoore(){
for(int i = 0 ; i < R ; i++){
right[i] = -1;
}
for( int i = 0 ; i < pattern.length() ; i ++ ){
right[pattern.charAt(i)] = i;
}
}
public int search(){
int m = pattern.length();
int n = text.length();
int skip;
for(int i = 0 ; i <= n - m ; i += skip){
skip = 0;
for( int j = m - 1 ; j >= 0 ;j --){
if( pattern.charAt(j) != text.charAt(i+j)){
skip = Math.max(1,j - right[text.charAt(i+j)]);
break;
}
}
if( skip == 0 ) return i;
}
return n;
}
This helped me understand how to use the TLA+ toolkit and execute the TLC Model checker even though the spec./code may have a bug.
But mainly I used
struct == [a |-> 97, b |-> 98, c |-> 99]
and a subset of values in the TLA Toolkit configuration section.
This section
CONSTANTS Character, text, pattern
ASSUME text \in Seq(Character)
ASSUME pattern \in Seq(Character)
uses the configured values when the model checker executes.
So now the state space is small. This was suggested to me by Stephan Merz when I asked the TLA+ Google group.
I tried a few methods and eventually set it up like this in the toolkit.
The original function that I was looking for is this.
Ascii(char) == 96 + CHOOSE z \in 1 .. 26 :"abcdefghijklmnopqrstuvwxyz"[z] = char
But this throws an error
----------------------------- MODULE bayermoore -----------------------------
EXTENDS Integers, Sequences,Naturals, TLC
CONSTANTS Character, text, pattern
ASSUME text \in Seq(Character)
ASSUME pattern \in Seq(Character)
Max(x,y) == IF x < y THEN y ELSE x
struct == [a |-> 97, b |-> 98, c |-> 99]
(*--algorithm bayermoore
variables
i,m,l,n,j,k,p,skips,x,y,
flag = [g \in 0..256 |-> -1];
begin
i := 1;
while i < Len(pattern) do
p := struct[pattern[i]];
flag[p] := 1;
i := i + 1;
end while;
i := 1;
m := Len(pattern);
n := Len(text);
k := n - m;
while i <= k do
skips := 0;
j := m - 1;
while j >= 0 do
x := struct[pattern[j+1]];
y := struct[text[i + j]];
\* print ( "x " \o ToString(x) \o "y " \o ToString(y) );
print ( "i " \o ToString(i) \o " j " \o ToString(j));
if x # y then
skips := Max(1,j - flag[y]);
j := -1;
end if;
j := j - 1;
end while;
i := i + skips;
print ("i - " \o ToString(i));
end while;
end algorithm; *)
I am trying to complete a task in MIPS.
It is needed to compare 2 strings in the next way: to count a number of each ascii symbol from 1 to 255 in both strings and and compare values for each symbol.
For a moment i have wrote piece of pseudo code in java just to visualize a problem. The part that i can't understand is how can i make a "search" of each ascii character in a string.
// array allAscii that suppose to contain all ascii symbols (i have made it
containing all zeros bacause in this java code it is not that much important)
int[] allAscii = new int[255]
String s1 = "ascii."; // first string
String s2 = "asciiz,"; // second string
int difference = 0;
for(int i = 0; i< allAscii.length; i++){
int count1 = 0; //counter for the character of the string1
int count2 = 0; //counter for the character of the string1
for(int k = 0; k<s1.length(); k++){
if( s1.charAt(k) == allAscii[i]) count1++;
}
for(int l = 0; l<s2.length(); l++){
if( s2.charAt(l) == allAscii[i]) count2++;
}
difference += Math.abs(count1- count2);
}
so as the result for strings "ascii." and "asciiz,"
symbols from 0 to 43: count1 = 0; count2 = 0; difference = 0;
',': count1 = 0; count2 = 1; difference = 1;
'.': count1 = 1; count2 = 0; difference = 1;
symbols from 47 to 96: count1 = 0; count2 = 0; difference = 0;
'a': count1 = 1; count2 = 1; difference = 0;
'c': count1 = 1; count2 = 1; difference = 0;
'i': count1 = 2; count2 = 2; difference = 0;
's': count1 = 1; count2 = 1; difference = 0;
'z': count1 = 0; count2 = 1; difference = 1;
and so on....
it is non needed to store amount of each letter. i need just to accumulate variable difference but i should run through ALL ascii symbols
I want to create a function in Delphi that computes different levels of two strings. If two strings are equal (ignoring case), then it should return 0, but if they are not equal, it should return the number of different characters. This function can be very useful for checking spelling.
function GetDiffStringLevel(S1,S2:string):Integer;
begin
if SameText(S1,S2) then Exit(0);
// i want get different chars count
end
samples code:
Diff:=GetDiffStringLevel('Hello','Hello');// Diff:=0;
Diff:=GetDiffStringLevel('Hello','2Hello');// Diff:=1;
Diff:=GetDiffStringLevel('Hello','H2ello');// Diff:=1;
Diff:=GetDiffStringLevel('Hello','Hello W');// Diff:=2;
Diff:=GetDiffStringLevel('Hello','World');// Diff:=6; or 5
Fast and compact implementation.
About 3 times as fast as smasher's implementation with normal strings.
More than 100 times as fast if one of the strings is empty.
Smasher's function is case insensitive though, which can be useful as well.
function LevenshteinDistance(const s, t: string): integer;inline;
var
d : array of array of integer;
n, m, i, j : integer;
begin
n := length(s);
m := length(t);
if n = 0 then Exit(m);
if m = 0 then Exit(n);
SetLength(d, n + 1, m + 1);
for i := 0 to n do d[i, 0] := i;
for j := 0 to m do d[0, j] := j;
for i := 1 to n do
for j := 1 to m do
d[i, j] := Min(Min(d[i-1, j]+1, d[i,j-1]+1), d[i-1,j-1]+Integer(s[i] <> t[j]));
Result := d[n, m];
end;
Note: the inline directive reduces the execution time to less than 70% on my machine, but only for the win32 target platform. If you compile to 64bits (Delphi XE2), inlining actually makes it a tiny bit slower.
What you want is known as the Levenshtein distance (the minimum number of edits to transform one string into the other, where an edit is either a character insertion, character deletion or character substitution). The wikipedia site has a pseudo code implementation.
Delphi implementation:
function LevenshteinDistance(String1 : String; String2 : String) : Integer;
var
Length1, Length2 : Integer;
WorkMatrix : array of array of Integer;
I, J : Integer;
Cost : Integer;
Val1, Val2, Val3 : Integer;
begin
String1 := TCharacter.ToUpper (String1);
String2 := TCharacter.ToUpper (String2);
Length1 := Length (String1);
Length2 := Length (String2);
SetLength (WorkMatrix, Length1+1, Length2+1);
for I := 0 to Length1 do
WorkMatrix [I, 0] := I;
for J := 0 to Length2 do
WorkMatrix [0, J] := J;
for I := 1 to Length1 do
for J := 1 to Length2 do
begin
if (String1 [I] = String2 [J]) then
Cost := 0
else
Cost := 1;
Val1 := WorkMatrix [I-1, J] + 1;
Val2 := WorkMatrix [I, J-1] + 1;
Val3 := WorkMatrix[I-1, J-1] + Cost;
if (Val1 < Val2) then
if (Val1 < Val3) then
WorkMatrix [I, J] := Val1
else
WorkMatrix [I, J] := Val3
else
if (Val2 < Val3) then
WorkMatrix [I, J] := Val2
else
WorkMatrix [I, J] := Val3;
end;
Result := WorkMatrix [Length1, Length2];
end;
I'm looking for a way in Delphi to validate and manipulate IP Addresses. Some of the things it should be able to do is...
Verify that a string is a valid IP address
Verify that a string is a valid subnet mask
Verify that an IP address is within a given Subnet
Some type (record or string or whatever) which is meant for storing an IP address
Basic conversion of an IP address types, such as String or Array[0..3] of Byte
Any other IP address routines that can make IP manipulation easier
The basic reason is that I want to see if these things are already out there before I go ahead and reinvent them.
I also once wrote a IPv4 and IPv6 conversion unit including a custom variant type for both types of IP addresses. This answer shows a few examples of its capabilities. Originally, it was designed to visualize values of various types in scale on some slider control 1). The requirements then were such that default existing libraries weren't sufficient, but I agree with the comments here that you probably will be helped with just Indy (10!) or alike.
Answering your list of questions with a few code snippets from that unit:
Q4: Storage type for IP types:
const
IPv4BitSize = SizeOf(Byte) * 4 * 8;
IPv6BitSize = SizeOf(Word) * 8 * 8;
type
T4 = 0..3;
T8 = 0..7;
TIPv4ByteArray = array[T4] of Byte;
TIPv6WordArray = array[T8] of Word;
TIPv4 = packed record
case Integer of
0: (D, C, B, A: Byte);
1: (Groups: TIPv4ByteArray);
2: (Value: Cardinal);
end;
TIPv6 = packed record
case Integer of
0: (H, G, F, E, D, C, B, A: Word);
1: (Groups: TIPv6WordArray);
end;
Q5: Conversion of IP address strings to these record or array types:
function StrToIPv4(const S: String): TIPv4;
var
SIP: String;
Start: Integer;
I: T4;
Index: Integer;
Count: Integer;
SGroup: String;
G: Integer;
begin
SIP := S + '.';
Start := 1;
for I := High(T4) downto Low(T4) do
begin
Index := PosEx('.', SIP, Start);
if Index = 0 then
IPv4ErrorFmt(SInvalidIPv4Value, S);
Count := Index - Start + 1;
SGroup := Copy(SIP, Start, Count - 1);
if TryStrToInt(SGroup, G) and (G >= Low(Word)) and (G <= High(Word)) then
Result.Groups[I] := G
else
Result.Groups[I] := 0;
Inc(Start, Count);
end;
end;
function StrToIPv6(const S: String): TIPv6;
{ Valid examples for S:
2001:0db8:85a3:0000:0000:8a2e:0370:7334
2001:db8:85a3:0:0:8a2e:370:7334
2001:db8:85a3::8a2e:370:7334
::8a2e:370:7334
2001:db8:85a3::
::1
::
::ffff:c000:280
::ffff:192.0.2.128 }
var
ZeroPos: Integer;
DotPos: Integer;
SIP: String;
Start: Integer;
Index: Integer;
Count: Integer;
SGroup: String;
G: Integer;
procedure NormalNotation;
var
I: T8;
begin
SIP := S + ':';
Start := 1;
for I := High(T8) downto Low(T8) do
begin
Index := PosEx(':', SIP, Start);
if Index = 0 then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Count := Index - Start + 1;
SGroup := '$' + Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Result.Groups[I] := G;
Inc(Start, Count);
end;
end;
procedure CompressedNotation;
var
I: T8;
A: array of Word;
begin
SIP := S + ':';
Start := 1;
I := High(T8);
while Start < ZeroPos do
begin
Index := PosEx(':', SIP, Start);
if Index = 0 then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Count := Index - Start + 1;
SGroup := '$' + Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Result.Groups[I] := G;
Inc(Start, Count);
Dec(I);
end;
FillChar(Result.H, (I + 1) * SizeOf(Word), 0);
if ZeroPos < (Length(S) - 1) then
begin
SetLength(A, I + 1);
Start := ZeroPos + 2;
repeat
Index := PosEx(':', SIP, Start);
if Index > 0 then
begin
Count := Index - Start + 1;
SGroup := '$' + Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
A[I] := G;
Inc(Start, Count);
Dec(I);
end;
until Index = 0;
Inc(I);
Count := Length(A) - I;
Move(A[I], Result.H, Count * SizeOf(Word));
end;
end;
procedure DottedQuadNotation;
var
I: T4;
begin
if UpperCase(Copy(S, ZeroPos + 2, 4)) <> 'FFFF' then
IPv6ErrorFmt(SInvalidIPv6Value, S);
FillChar(Result.E, 5 * SizeOf(Word), 0);
Result.F := $FFFF;
SIP := S + '.';
Start := ZeroPos + 7;
for I := Low(T4) to High(T4) do
begin
Index := PosEx('.', SIP, Start);
if Index = 0 then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Count := Index - Start + 1;
SGroup := Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Byte)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
case I of
0: Result.G := G shl 8;
1: Inc(Result.G, G);
2: Result.H := G shl 8;
3: Inc(Result.H, G);
end;
Inc(Start, Count);
end;
end;
begin
ZeroPos := Pos('::', S);
if ZeroPos = 0 then
NormalNotation
else
begin
DotPos := Pos('.', S);
if DotPos = 0 then
CompressedNotation
else
DottedQuadNotation;
end;
end;
For Q1 to Q3 you have to derive some routines yourself, but that should not be any problem.
1) For those interested, it's this slider control and this topic served as initiation of this unit.
I have already written all the functions you require but I'm afraid I'm not in a position to share the code.
However, the Synapse library contains quite a few functions in the synaip unit. e.g.
function IsIP(const Value: string): Boolean;
function IsIP6(const Value: string): Boolean;
function IPToID(Host: string): Ansistring;
function StrToIp6(value: string): TIp6Bytes;
function Ip6ToStr(value: TIp6Bytes): string;
function StrToIp(value: string): integer;
function IpToStr(value: integer): string;
function ReverseIP(Value: AnsiString): AnsiString;
function ReverseIP6(Value: AnsiString): AnsiString;
When I tried the functions a few years ago, the IPv6 functions were a bit buggy, especially when dealing with compressed IPv6 addresses.
If you want to roll your own, here a few pointers:
Manipulating IPv4 addresses is fairly simple as they only consist of
32 bits which can be stored in a standard integer type. IPv6
addresses are harder as they need 128 bits and no native type has
that many bits.
Before trying to manipulate an IP address, first convert it into an
integer (IPv4 only of course, IPv6 will require a different storage
method). To do this, split the IP address using '.' as a delimiter.
Check each individual value only contains numbers and falls between 0
and 255 then use these values to generate the final integer.
Once the IP address has been converted into an integer, you can
manipulate it however you like. For example, given an IP address and
a subnet mask you can find the subnet that the IP address belongs to
e.g. IPtoInt(IPAddress) AND NOT(IPToInt(SubnetMask)) = The integer of
the subnet. Now, you can comaare an integer IP address to the integer
subnet to see if the IP falls within the subnet.
Finally, convert the integer IP address back into a string.
If you have any specific questions I can try to answer them too.
I have a variety of strings which I need to work with, these contain both letters and numbers , I am trying to extract the numbers (which is the part I need) from the string, the strings would have a similar format to -
the cat can count 123 567 so can the dog"
The length and position of the numbers can vary from
12 34
123 456
1234 5678
11111 11111
Also the number seperator can vary from a space question mark and also a dash
12-34
12.34
So the string could be EG “the cat can't count, the dog can 12-67” or “the cat can count 1234.5678 so can the dog”
Is there any clever way in Delphi I can extract the numbers? Or would I have to do it by scanning the string in code.
Any help would be appreciated
Thanks
colin
If you have Delphi XE or up, you can use regular expressions. This is completely untested, based on David Heffernan's answer:
function ExtractNumbers(const s: string): TArray<string>;
var
regex: TRegEx;
match: TMatch;
matches: TMatchCollection;
i: Integer;
begin
Result := nil;
i := 0;
regex := TRegEx.Create("\d+");
matches := regex.Matches(s);
if matches.Count > 0 then
begin
SetLength(Result, matches.Count);
for match in matches do
begin
Result[i] := match.Value;
Inc(i);
end;
end;
end;
I think this function is what you are looking for:
function ExtractNumbers(const s: string): TArray<string>;
var
i, ItemIndex: Integer;
LastCharWasDigit: Boolean;
len: Integer;
Count: Integer;
Start: Integer;
begin
len := Length(s);
if len=0 then begin
Result := nil;
exit;
end;
Count := 0;
LastCharWasDigit := False;
for i := 1 to len do begin
if TCharacter.IsDigit(s[i]) then begin
LastCharWasDigit := True;
end else if LastCharWasDigit then begin
inc(Count);
LastCharWasDigit := False;
end;
end;
if LastCharWasDigit then begin
inc(Count);
end;
SetLength(Result, Count);
ItemIndex := 0;
Start := 0;
for i := 1 to len do begin
if TCharacter.IsDigit(s[i]) then begin
if Start=0 then begin
Start := i;
end;
end else begin
if Start<>0 then begin
Result[ItemIndex] := Copy(s, Start, i-Start);
inc(ItemIndex);
Start := 0;
end;
end;
end;
if Start<>0 then begin
Result[ItemIndex] := Copy(s, Start, len);
end;
end;
function ExtractNumberInString ( sChaine: String ): String ;
var
i: Integer ;
begin
Result := '' ;
for i := 1 to length( sChaine ) do
begin
if sChaine[ i ] in ['0'..'9'] then
Result := Result + sChaine[ i ] ;
end ;
end ;
inspired by user2029909 response
function ExtractNumberInString (sChaine: String; Start : Integer = 1): TArray<String> ;
var
i, j: Integer ;
TmpStr : string;
begin
j := 0;
for i := Start to Length( sChaine ) do
begin
if sChaine[ i ] in ['0'..'9'] then
TmpStr := TmpStr + sChaine[ i ]
else
if TmpStr <> '' then
begin
SetLength(Result, Length(Result) + 1);
Result[j] := TmpStr;
TmpStr := '';
Inc(j);
end;
end ;
end ;
EDIT 1.: The function below will read the first floating point number after the position Start in the String S and register its end position as Last. This function does NOT work for different cases of float numbers, such as:
3.1415926535897932384d0; A double-format approximation to Pi
3.010299957f-1; Log2, in single format
-0.000000001s9 e^(i*Pi), in short format
0.0s0; A floating-point zero in short format
0s0; Also a floating-point zero in short format
https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node19.html
function ExtractFloatStr(Start : integer; S : string; var Last : integer) : string;
var
i, Lstr : integer;
chln : char;
str_acm : string;
Numeric, Sign, DeciSep, Exponent : boolean;
begin
Numeric := False; Sign := False; DeciSep := False; Exponent := False;
Lstr := length(S);
If (Start > 0) and (Start <= Lstr) then
i := Start-1
Else i := 0;
Last := -1; chln := #0;
str_acm := '';
repeat
begin
i := i + 1;
chln := S[i];
//ShowMessage('str_acm['+IntToStr(i)+'] = '+str_acm+'P');
If Last = -1 then
begin
If chln = '-' then
begin
{ Signs will only count if they are the first element }
If (str_acm = '') then { Signs can only be added at the leftmost position }
begin
Sign := True;
str_acm := str_acm + chln;
end
{ If there's something already registered as number, a right-side Sign will mean two things }
Else begin
{ Signs cannot be added at the right side of any number or Decimal Separator }
If Numeric = True then { End of the reading, in case there's already a valid series of digits }
begin
{Last := i-1;} { ex.: -1.20----; -.20--- }
If i > 1 then
begin
If (S[i-1] = 'E') or (S[i-1] = 'e') then
str_acm := str_acm + chln
Else begin
Last := i-1;
end;
end;
end
Else begin { A mixture of various characters without numeric logic}
str_acm := ''; { So start over the reading }
Sign := False; { ex.: -.--- }
end;
end;
end;
If (chln in ['.',',']) then
begin
If (DeciSep = False) then { Decimal Separators can only be added once }
begin
str_acm := str_acm + DecimalSeparator;
DeciSep := True;
end
{ If a Decimal Separator was already accounted, a second one will mean two things }
Else begin
If Numeric = True then { End of the reading, in case there's already a valid series of digits }
Last := i-1 { ex.: -1.20...; -0.20. }
Else begin { A mixture of various characters without numeric logic }
str_acm := ''; { So start over the reading }
DeciSep := False; { ex.: -... }
end;
end;
end;
If (chln in ['0'..'9']) then
begin
Numeric := True; { Numbers can be added after any other characters, be it Sign and/or Decimal Separator }
str_acm := str_acm + chln; { Ex.: -1; -2.1; -.1; -1. }
end;
If (chln = 'E') or (chln = 'e') then
begin
If Exponent = False then
begin
If Numeric = True then { E for the power of 10 can only be added once and after a series of digits }
begin { Ex.: 1.0E10; -.0E2; -4.E3 }
str_acm := str_acm + chln;
Exponent := True;
end
Else begin { The abscense of a previous series of digits does not allow the insertion of E }
str_acm := ''; { E cannot start a floating point number and cannot succeed a sign or }
end; { decimal separator if there isn't any previous number }
end { Ex.: -.E; .E; -E; E }
Else begin
Last := i-1; { E cannot appear twice. A second one means the end of the reading }
end;
end;
If chln = '+' then { Plus (+) sign will only be registered after a valid exponential E character }
begin
If (i > 1) and (Exponent = True) then
begin
If (S[i-1] = 'E') or (S[i-1] = 'e') then
str_acm := str_acm + chln
Else begin
Last := i-1; { If it's added after anything other than E, the reading ends }
end;
end;
If Exponent = False then
begin
If (Numeric = True) then
begin
Last := i-1; { If it's added after anything other than E, the reading ends }
end
Else begin
str_acm := ''; { If it's added after anything other than E, and if there isn't any }
Exponent := False; { valid series of digits, the reading restarts }
end;
end;
end;
{ If any character except the ones from the Floating Point System are added }
If not (chln in ['0'..'9','-','+',',','.','E','e']) then
begin
{ After an already accounted valid series of digits }
If (str_acm <> '') then
begin
If (Numeric = True) then
Last := i-1 { End of the reading. Ex.: -1.20A; -.20%; 120# }
Else begin
str_acm := '';
Sign := False; DeciSep := False; Exponent := False;
end;
end;
end;
end;
//ShowMessage('i = '+IntToStr(i)+#13+str_acm+'P');
end;
until((Last <> -1) or (i = Lstr));
If (i = Lstr) and (Numeric = True) then
Last := i;
{ The Loop does not filter the case when no number is inserted after E, E- or E+ }
{ So it's necessary to check and remove if E,E-,E+,e,e-,e+ are the last characters }
If Last <> -1 then
begin
Lstr := length(str_acm);
If (str_acm[Lstr] = '+') or (str_acm[Lstr] = '-') then
begin
SetLength(str_acm,Lstr-1);
Last := Last - 1;
end;
Lstr := length(str_acm);
If (str_acm[Lstr] = 'E') or (str_acm[Lstr] = 'e') then
begin
SetLength(str_acm,Lstr-1);
Last := Last - 1;
end;
Result := str_acm;
end
Else Result := '';
end; { ExtractFloatStr }
EDIT 2.: Another function using the previous one to read a series of numbers in the same string.
var
TFloatType = real;
TVetorN = array of TFloatType;
procedure ExtractFloatVectorStr(Str : string; var N : integer; var FloatVector : TVetorN);
var { Extract floating point numbers from string reading from left to right }
i, j, k, Lstr, Lstr1 : integer; { Register the numbers in FloatVector as the type TVetorN }
char1 : char; { Register the amount of numbers found as the integer N }
str_acm : string;
begin
Str := AdjustLineBreaks(Str,tlbsCRLF);
Lstr := length(Str);
Lstr1 := 0;
char1 := #0;
i := 1; j := 0; k := 0; str_acm := '';
SetLength(FloatVector,j+1);
repeat
begin
If (i <= Lstr) then
begin
str_acm := ExtractFloatStr(i, Str, k);
Lstr1 := length(str_acm);
If (Lstr1 > 0) and (str_acm <> '') then
begin
j := j + 1;
SetLength(FloatVector,j+1);
FloatVector[j] := StrToFloat(str_acm);
i := k + 1;
end
Else i := i + 1;
end;
end;
until(i > Lstr);
N := j;
end; { ExtractFloatVectorStr }