Jump to content
Developer Wiki and Function Reference Links Read more... ×
Paolo

Function (or procedure) that returns dynarray[]of char

Recommended Posts

I am trying to develop an SVG reader in Vectorscript, but I am at a stake because of the impossibility to manage functions or procedures that calculate and return strings that may have more than 255 chars.
Having to do with SVG commands like this…

<path fill="none" stroke="#000000" stroke-width="0.238" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-dasharray="1,1" d="
    M47.506,645.356c0.099,0,0.197-0.049,0.296-0.049c0.098,0,0.196-0.05,0.295-0.099s0.197-0.049,0.296-0.099
    c0.098-0.049,0.196-0.099,0.246-0.147c0.098-0.049,0.196-0.099,0.246-0.147c0.098-0.05,0.147-0.099,0.246-0.148
    c0.099-0.049,0.147-0.147,0.246-0.196c0.049-0.05,0.147-0.148,0.196-0.197c0.05-0.049,0.148-0.147,0.197-0.246
    s0.099-0.147,0.197-0.246c0.049-0.099,0.098-0.147,0.147-0.246c0.049-0.099,0.099-0.197,0.147-0.295
    c0.05-0.148,0.147-0.296,0.197-0.493c0.049-0.147,0.099-0.295,0.196-0.492c0.05-0.147,0.099-0.345,0.148-0.492
    c0.049-0.196,0.147-0.442,0.196-0.64c0-0.05,0.05-0.147,0.05-0.197c0-0.049,0.049-0.147,0.049-0.197
    c0-0.049,0.05-0.147,0.05-0.196c0-0.05,0.049-0.147,0.049-0.197c0-0.049,0-0.049,0-0.099c0-0.049,0-0.049,0-0.098
    c0-0.05,0-0.05,0-0.099c0-0.05,0-0.05-0.049-0.099c0-0.049-0.05-0.049-0.05-0.049l-0.049-0.05l-0.05-0.049
    c-0.049,0-0.049-0.05-0.099-0.05c-0.049,0-0.049,0-0.098,0c-0.05,0-0.05,0-0.099,0c-0.05,0-0.05,0-0.099,0s-0.049,0-0.099,0.05
    c-0.049,0-0.049,0.049-0.099,0.049l-0.049,0.05l-0.049,0.049c0,0-0.05,0.049-0.05,0.099c0,0.049-0.049,0.099-0.049,0.147
    s-0.05,0.099-0.05,0.147c0,0.05-0.049,0.099-0.049,0.148c0,0.049-0.049,0.098-0.049,0.147c-0.05,0.099-0.099,0.246-0.197,0.345
    c-0.05,0.099-0.099,0.246-0.197,0.345c-0.099,0.147-0.147,0.246-0.246,0.394s-0.147,0.246-0.246,0.394s-0.197,0.246-0.246,0.345
    s-0.147,0.147-0.197,0.246c-0.049,0.099-0.147,0.147-0.196,0.197c-0.05,0.049-0.147,0.147-0.197,0.196
    c-0.049,0.05-0.147,0.148-0.246,0.197s-0.147,0.099-0.246,0.147c-0.099,0.05-0.147,0.099-0.246,0.148
    c-0.099,0.049-0.197,0.098-0.246,0.147c-0.099,0.049-0.197,0.099-0.296,0.147c-0.147,0.049-0.295,0.099-0.442,0.147
    c-0.147,0.05-0.296,0.099-0.443,0.148c-0.147,0.049-0.295,0.098-0.443,0.147c-0.098,0.049-0.196,0.049-0.295,0.099
    c-0.099,0-0.197,0.049-0.296,0.049c-0.049,0-0.147,0.049-0.196,0.049c-0.05,0-0.147,0-0.197,0.05c-0.049,0-0.147,0-0.196,0.049
    c-0.05,0-0.148,0-0.197,0.05c-0.05,0-0.05,0-0.099,0s-0.049,0-0.099,0.049c-0.049,0-0.049,0.049-0.049,0.049l-0.05,0.05
    l-0.049,0.049c0,0.05-0.049,0.05-0.049,0.099s0,0.049,0,0.099c0,0.049,0,0.049,0,0.099c0,0.049,0,0.049,0,0.098
    c0,0.05,0,0.05,0.049,0.099c0,0.05,0.049,0.05,0.049,0.099l0.05,0.049l0.049,0.05c0,0,0.05,0.049,0.099,0.049s0.049,0,0.099,0.05
    c0.049,0,0.049,0,0.099,0c0.049,0,0.099,0,0.147,0s0.099,0,0.147,0c0.05,0,0.099,0,0.147,0c0.05,0,0.099,0,0.148,0
    c0.147,0,0.295,0,0.442,0c0.148,0,0.296,0,0.443,0s0.345,0,0.492-0.05c0.147,0,0.345-0.049,0.492-0.049
    C47.161,645.406,47.359,645.406,47.506,645.356z”/>

… that goes very beyond the 255 chars strings limit, I had necessarily to substitute functions returning strings into functions returning dynarray[]of char, but this is FORBIDDEN.
So I tried with procedures returning dynarray[]of char as VAR (this is allowed) but I found strange behaviors.

 

For example, the following script takes the constant string (this is a short string, just for instance).
The first procedure extracts the substring starting from 'points="' and the subsequent '"'.
The second procedure replaces the commas with spaces.
Both procedure uses the same VAR s:string declared.

procedure test;
const
polygon = '<polygon  points="35.938,135.145 36.233,140.511     36.971,140.511 36.971,135.145     "/>’; 
{this is just an example of SVG line, this is < 256 chars, but this is a special case}
    
var
s: dynarray[]of char; {declare the VAR I'll use later as value returned from procedures}
    
{*********************** scanPolyPoints **********************}
{return the substring between 'points="' and '"', I'll split these points later}
procedure scanPolyPoints(parameter: string; line: DYNARRAY[] OF CHAR; var r:DYNARRAY[] OF CHAR);
var
index1, index2: integer;
temp: DYNARRAY[] OF CHAR;
begin
{search the position of 'parameter='}
index1 := Pos(parameter, line)+1+len(parameter);
temp := copy(line, index1, len(line)-index1); {remaining string} 
{search the position of '"' in the remaining string}
index2 := Pos('"', temp);
temp := copy(temp, 1, index2-1); {here I have only the string composed by points} 
r := temp; {set the answer r}
end;

{*********************** replaceCommas **********************}
{substitute each comma with a space and each minus signs with ' -'}
{in the SVG (generated by Adobe Illustrator), the path numbers are separated by a ',' or by '-' or by a space}
{whenever you find a '-', the ',' is omitted!}
procedure replaceCommas(source:dynarray[]of char; var dest: dynarray[]of char);
var
i:integer;
temp: string;
begin
temp := '';
for i:=1 to len(source) do
begin
if source[i] = ',' then temp:=Concat(temp,' ')
    else if source[i] = '-' then temp:=Concat(temp,' -')
    else temp:=Concat(temp,source[i])
end;
dest := temp;
end;
begin
s := ''; {init}
writeln(polygon); {write the input string to the standard output}
scanPolyPoints(' points=', polygon, s); {first procedure}
writeln(s); {write the resulting "s" string to the standard output}
{Now I use the variable s both as parameter and resulting var}
replaceCommas(s, s); {second procedure, commas should be replaced by spaces}
writeln(s); {but NO! It's unchanged}
{test it with a constant string as parameter…}
replaceCommas('.,.,.,.,.,.,.,', s);
writeln(s); {…it works!}
end;
run(test);    

The resulting output is the following:

<polygon  points="35.938,135.145 36.233,140.511             36.971,140.511 36.971,135.145         "/>
35.938,135.145 36.233,140.511             36.971,140.511 36.971,135.145         
35.938,135.145 36.233,140.511             36.971,140.511 36.971,135.145         
. . . . . . . 

As you can see, the first procedure works (line 2), the second no (line 3 has still commas in place!). While the constant string has the commas removed (line 4).

Where is the problem and, most of all, is there a solution?

 

Thank you for any help.

Paolo Marcuccetti

 


 

Share this post


Link to post

If you would output the string in a file, may be the solution would be to write directly the file and not to try to store it in a string.

 

Sorry, you seem to read the SVG. So only read what is needed for what you parse, not more.

Edited by Nicolas Goutte

Share this post


Link to post

 replaceCommas( s, s ) is a bit irregular. You are essentially passing both a copy of and a reference to the same variable, which is unnecessary, as the VAR (reference) syntax gives you both read and write access. 

 

Your code can be much simpler if the arguement is a single VAR dynarray of char:

 

For i := 1 to len(inStr) do begin

     if inStr = ‘,’ then

          inStr := ‘ ‘

end;

 

Sometimes dynarrays of chr need a sort of reset if the length changes. Str := Concat(str) will work. 

 

All that said, I highly recommend looking into python for this script. If you’re new to VS, python is going to be much easier to learn. If not, most of the vs functions you’re familiar with still work in python — just double check the syntax. 

 

Python is is designed for parsing data, so you won’t have to reinvent the wheel for iterating, extracting, and replacing. I also believe there are existing svg modules for python that you can take advantage of. 

  • Like 1

Share this post


Link to post

Yes, indeed, if you are not bound to use Vectorscript for a reason or another, I too would recommend using Python for such a task.

Edited by Nicolas Goutte
  • Like 1

Share this post


Link to post

Ok, I'll try to port to python all the project.

However, I've tried to reset the variable as suggested

 

s := Concat('',s);


and it works!

Edited by Paolo
Postscriptum

Share this post


Link to post

I only took a really quick look, but I don't see where you are storing the Temp back into the original string/array.

 

I think you need to DELETE the original command and INSERT the temp at the same location.

 

Python is certainly better at string manipulation, but this is well within the capability of VS.

Share this post


Link to post

Here's the script with the var passed as reference.

It works only when you apply the trick

s:=concat('', s);

The result is a list of valid real numbers delimited by spaces, to be splitter later:

35.938 135.145 36.233 140.511 36.971 140.511 36.971 135.145 145

 

I'll try to port these in python. I do not know python, while I am an old Vectorscript developer.

I hope python has a better array management (count, split etc.) as any modern language should.

procedure trim;
const
testString = '<polygon  points="35.938,135.145 36.233,140.511     36.971,140.511 36.971,135.145     "/>';
var
r: dynarray[]of char;
procedure trimNotInList(list: DYNARRAY[] OF CHAR; VAR s: dynarray[]of char);
VAR
    i : INTEGER;
    t : dynarray[]of char;
BEGIN
    t := s;
    i := 1;
    WHILE i <= Len(t) DO
        IF (Pos(Copy(t, i, 1), list) = 0) THEN
            Delete(t, i, 1)
        ELSE
            i := i + 1;
    s := t;
END;
procedure runOfSpacesIntoOne(var s:dynarray[]of char);
var
i:integer;
temp: dynarray[] of char;
begin
s := Concat('',s); {pseudo reset}
temp := '';
for i:=1 to len(s) do
begin
temp:=concat(temp, s[i]);
if (i>1) then
    if (s[i]=' ') and (s[i-1]=' ') then 
        temp := copy(temp, 1, len(temp)-1);
end;
s := temp;
end;
procedure trimSpaces(var s:dynarray[] of char);
var
i, ti, te:integer;
begin
s := Concat('',s); {pseudo reset}
    for i:=1 to len(s) do
    begin
        ti :=i;
        if s[i] <> ' ' then i := len(s); {esco dal for}
    end;
    for i:=len(s) downto 1 do
    begin
        te := i;
        if s[i] <> ' ' then i := 1; {esco dal for}
    end;
s := copy(s, ti, te-ti+1);
end;
procedure replaceCommas(var s: dynarray[]of char);
var
i:integer;
temp: string;
begin
s := Concat('',s); {pseudo reset}
temp := '';
for i:=1 to len(s) do
begin
if s[i] = ',' then temp:=Concat(temp,' ')
    else if s[i] = '-' then temp:=Concat(temp,' -')
    else temp:=Concat(temp,s[i])
end;
s := temp;
end;
{*********************** scanPolyPoints **********************}
{return the substring between 'points="' and '"', I'll split these points later}
procedure scanPolyPoints(parameter: string; line: DYNARRAY[] OF CHAR; var r:DYNARRAY[] OF CHAR);
var
index1, index2: integer;
temp: DYNARRAY[] OF CHAR;
begin
index1 := Pos(parameter, line)+1+len(parameter);
temp := copy(line, index1, len(line)-index1);
index2 := Pos('"', temp);
temp := copy(temp, 1, index2-1);
temp := concat('', temp);
trimNotInList('0123456789+-,. ',temp);
replaceCommas(temp);
runOfSpacesIntoOne(temp);
r := temp; 
trimSpaces(r);
end;

begin
r:=teststring;
scanPolyPoints(' points=', teststring, r);
writeln(r);
end;
run(trim);

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

 

7150 Riverwood Drive, Columbia, Maryland 21046, USA   |   Contact Us:   410-290-5114

 

© 2018 Vectorworks, Inc. All Rights Reserved. Vectorworks, Inc. is part of the Nemetschek Group.

×