String manipulation for VML Path

2019-09-06 19:07发布

问题:

Hi I am trying to parse VML Path value using Java String manipulation. I want to retreive all the commands in the path like MoveTo, LineTo, CurveTo, RLineTo (other commands) and their corresponding x and y coordinates/parameters.

Here are example data to parse, each command has their own x,y coordinates.

 1. m1,1 l1,200,200,200,200,1 xe
 2. m, l1,200,200,200,200,1 xe

Can you suggest an algorithm or code on retreiving the commands and the parameters for each command? For example in number 1.

Command = moveto 'm'

Command Parameters = (x=1,y=1).

Ref: http://www.w3.org/TR/NOTE-VML#_Toc416858391

This is something weird but I tried using StringTokenizer like

StringTokenizer tokenizer = new StringTokenizer(path);

A friend suggested using StringTokenizer and it did something near to my goal, it gave me the following data. Maybe I can utilize StringTokenizer to suit my needs.

m1,1
l1,200,200,200,200,1
xe

For #1, here is the ideal output. (pseudocode)

String command_type = "m"        List<String, String> parameters =   add("1", "1")
String command_type = "l"        List<String, String> parameters =   add("1", "200")
                                                                     add("200", "200")
                                                                     add("200", "1")
String command_type = "x"        (can have no parameter )
String command_type = "e"        (can have no parameter )

For #2, here is the ideal output. (pseudocode)

String command_type = "m"        List<String, String> parameters =   add("0", "0")  // because the x and y parameters are not specified so I need to force them to 0,0
String command_type = "l"        List<String, String> parameters =   add("1", "200")
                                                                     add("200", "200")
                                                                     add("200", "1")
String command_type = "x"        (can have no parameter )
String command_type = "e"        (can have no parameter )

回答1:

A good spec is important here but based on your sample input and output I have guessed:

Letter -> comma separated parameters -> letter -> comma separated parameters

I have also noted that commands are not separated by spaces. e.g. you have xe as two separate commands. This means that in your sample spaces have no meaning and can be ignored.

I also note that commands are all single letters. (Otherwise xe wouldn’t come as two commands)

Also Parameters must come in pairs and must be numbers. I see no negative numbers in your sample but I assume that these are possible. I will also assume that they are integers and not decimals.

So based on the assumed spec I can come up with a possible solution for you to have a look through and work out what it is doing.

package ic.ac.uk.relationshipvisualiser.app;

import java.util.ArrayList;
import java.util.List;

public class TmpNoFXTest {

    private static class coOrd {
        int x = 0;
        int y = 0;
        public coOrd(int p_x,int p_y) {
            x=p_x;y=p_y;
        }
        public int getX() {return x;}
        public int getY() {return y;}
    }
    private static class command {
        String command = "";
        List<coOrd> param_list = new ArrayList<coOrd>();

        public command(String p_command) {
            command = p_command;
        }
        private String parseOneParam(String p_inp) {
            if (p_inp.equals("")) return "";
            if (isLetter(p_inp.substring(0,1))) return p_inp;
            int firstChar = 0;
            for (int c=0;c<p_inp.length();c++) {
                if (firstChar==0) {
                    if (isLetter(p_inp.substring(c,c+1))) {
                        firstChar = c;
                    }
                }
            }

            String parms = p_inp.substring(0,firstChar);
            if (parms.length()==0) return p_inp.substring(firstChar);
            int x = 0;
            int y = 0;

            int p = 0;
            String tmp = "";
            while ((p<parms.length()) && (!parms.substring(p,p+1).equals(","))) {
                tmp = tmp + parms.substring(p,p+1);
                p++;
            }
            p++;
            if (tmp.length()>0) {
                x = Integer.parseInt(tmp);
            }

            tmp = "";
            while ((p<parms.length()) && (!parms.substring(p,p+1).equals(","))) {
                tmp = tmp + parms.substring(p,p+1);
                p++;
            }

            if (p_inp.substring(p,p+1)==",") p++;

            if (tmp.length()>0) {
                y = Integer.parseInt(tmp);
            }

            param_list.add(new coOrd(x,y));

            return p_inp.substring(p);
        }
        public String parseParams(String p_inp) {
            if (p_inp.equals("")) return "";
            while (!isLetter(p_inp)) {
                p_inp = parseOneParam(p_inp);
            }
            return p_inp;
        }
        public String toString() {
            String ret = "";
            ret = "String command_type = \"" + command + "\"";
            if (param_list.size()==0) return ret + "     (can have no parameter )";


            for (int c=0;c<param_list.size();c++) {
                if (c>0) ret += "\n                         ";
                ret += "        List<String, String> parameters =   add(\"" + param_list.get(c).getX() + "\", \"" + param_list.get(c).getY() + "\")";               
            }

            return ret;
        }
    }
    private static boolean isLetter(String p_inp) {
        return p_inp.substring(0,1).matches("\\p{L}");
    }


    private static String parseSingleCommand(String p_inp, List<command> p_cmds) throws Exception {
        //Read a single command off the incoming string and pass the remaining input back

        String cmd = p_inp.substring(0,1);
        if (!isLetter(p_inp)) throw new Exception("Error command starts with non letter (" + cmd + ")");


        p_inp = p_inp.substring(1);
        command c = new command(cmd);
        p_inp = c.parseParams(p_inp);

        p_cmds.add(c);
        return p_inp;
    }

    private static List<command> parse(String p_inp) throws Exception {
        List<command> r = new ArrayList<command>();

        //spaces don't matter and I want to make this case-insensitive to minimise errors
        p_inp = p_inp.toLowerCase();
        p_inp = p_inp.replace(" ", "");

        while (p_inp.length()>0) {
            p_inp = parseSingleCommand(p_inp,r);
        }
        return r;
    }

    public static void main(String[] args) {
        System.out.println("Start tmpTest");

        List<String> tests = new ArrayList<String>();
        tests.add("m1,1 l1,200,200,200,200,1 xe");
        tests.add("m, l1,200,200,200,200,1 xe");

        for (int c=0;c<tests.size();c++) {
            System.out.println("Running test case " + c + " (" + tests.get(c) + ")");
            try {
                List<command> pr = parse(tests.get(c));

                for (int d=0;d<pr.size();d++) {
                    System.out.println(pr.get(d).toString());
                }

            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
        };

        System.out.println("End tmpTest");
    }
}