StringTokenizer

Former Member
Former Member
Hi,

does it exist a class like StringTokenizer (I don't see it in the API) , that parse a string by giving it a special character, or do we need to re create it ?

Thanks
  • You must create it. That should be pretty easy to do though. I'm writing this without the aid of a compiler, so it may not work...

    function split(s, sep) {
    var tokens = [];

    var found = s.find(sep);
    while (found != null) {
    var token = s.substring(0, found);
    tokens.add(token);

    s = s.substring(found + sep.length(), s.length());

    found = s.find(sep);
    }

    tokens.add(s);

    return tokens;
    }


    I think the following should be a reasonable start on a unit test as well.

    using Toybox.Lang as Lang;
    using Toybox.Test as Test;

    (:test)
    function test_split(logger) {
    var dot = ".";

    var scenarios = [
    { :s => "", :sep => dot, :expect => [ "" ] },
    { :s => ".", :sep => dot, :expect => [ "", "" ] },
    { :s => ".a", :sep => dot, :expect => [ "", "a" ] },
    { :s => "a", :sep => dot, :expect => [ "a" ] },
    { :s => "a.", :sep => dot, :expect => [ "a", "" ] },
    { :s => "a.b", :sep => dot, :expect => [ "a", "b" ] },
    { :s => "a.b.", :sep => dot, :expect => [ "a", "b", "" ] }
    ];

    var passed = true;

    for (var i = 0; i < scenarios.size(); ++i) {
    var scenario = scenarios;

    var s = scenario[:s];
    var sep = scenario[:sep];
    var expect = scenario[:expect];

    var result = split(s, sep);

    // hack around broken Array.equals() failing for arrays with same values
    var s1 = result.toString();
    var s2 = expect.toString();

    // print every assertion we do so we see a summary of what was tested and
    // what passes or fails
    var message = Lang.format("split($1$, $2$) returned '$3$', expected '$4$'", [ s, sep, result, expect ]);
    if (s1.equals(s2)) {
    logger.debug(message);
    }
    else {
    logger.error(message);
    passed = false;
    }

    // we could use this, but we get no output if the assert passes and
    // if one assertion fails we don't run any more of them.

    // hack around assertEqualsMessage(a, b, message) using `a == b'
    //Test.assertMessage(
    // s1.equals(s2),
    // Lang.format("split($1$, $2$) returned '$3$', expected '$4$'", [ s, sep, result, expect ])
    //);
    }

    return passed;
    }
    [/code]

    If you want split() to work with ConnectIQ 1.2, you'd have to either count the separators first and allocate the array, or grow the array as you append.

    Travis
  • Former Member
    Former Member over 8 years ago
    Great thanks Travis.

    Rgds
  • Former Member
    Former Member over 8 years ago
    Hi Travis,

    I'm trying to test your method, but I have issues (it's normal because you don't test it), but I don't understand them ... As I'm not very familiar with arrays ...
    I put so System.println to see what the method do :


    function split(s, sep) {
    var tokens = []; //This works ? No need for initialisation ? This is good for me, but as I have errors, I asked me if this was not there the problem

    var found = s.find(sep);
    while (found != null) {
    var token = s.substring(0, found);
    tokens.add(token);

    s = s.substring(found + sep.length(), s.length());

    found = s.find(sep);
    }

    tokens.add(s);
    System.println("tokens = "+tokens); //This failed, I don't understand why

    return tokens;
    }



    Thanks for your help
  • Former Member
    Former Member over 8 years ago
    Thanks easuvorov,

    // split receives length of [number of elements], since we have less than 10 elements, lengths of 1 character can be used


    If we have more, we used the length of 2 ?

    How to estimate the good length to give ?

    Thanks
  • Former Member
    Former Member over 8 years ago
    In above implementation there's no "good length to give", you have to prepare string in said format and you have to know element count length in characters beforehand.

    E.g. another static labels string I use is "17 56 62 66 73 86 89 91104115120126132140143149155162171ResumeSaveDiscardAre you sure?YesNoActivity TypeData FieldsOrderActiveAlertsSettingsNewDeleteLowestHighestSend Data". In this example there are 17 elements, thus I have to use split(2,...) and subst(2,...). Memory consumption comparison showed that there is around 300 bytes economy just by converting 17 separate labels into one string, and I'm not considering wrapping code to use separate labels instead of one-time resource loading and sequential subst()'s after that.

    If you want to make it even more versatile, no one prevents you to change this string format and give several first character to define something like "first start position" or "record length" etc. Just play with precalculated values and find what best suits you performance and memory wise. In my case there was no need for a complete DBF-alike replacement, so I stopped with the above code.
  • Former Member
    Former Member over 8 years ago
    249

    ok, thanks
  • I'm trying to test your method, but I have issues (it's normal because you don't test it), but I don't understand them

    I updated the test code to work.

    I put so System.println to see what the method do

    The line of code you added works fine in the simulator. I believe it might not work correctly on devices unless you explicitly convert the list to a string like this...

    Sys.println("tokens=" + tokens.toString());


    Travis
  • Former Member
    Former Member over 8 years ago
    Yes Travis,
    it works since I remove my System.println ...

    Thanks ...