1

Working on a bit of an interesting project and I'm having a little trouble writing regex for this.

Using regex and Javascript, I want to split my input string into an array of "keys". Strings that have an invalid key should return 0 keys (null, empty array, whatever is fine).

The "spec"

<input string>      => <matches>

# named keys
a                   => ['a']
b                   => ['b']
foo[bar]            => ['foo', 'bar']

# numeric keys are ok too
a[0]                => ['a', '0']
b[1]                => ['b', '1']

# 'push' syntax is also valid
push[]              => ['push', '']
hello[]             => ['hello', '']

# complex!
complex[named][0][] => ['complex', 'named', '0', '']

Invalid examples

# named keys must start with [a-zA-Z]
_invalid            => null
3foo[abc]           => null

# named keys can include a number as long as they start with a letter
foo3valid[this_is_valid_2] => ['foo3valid', 'this_is_valid_2']

What I have so far

var regex = /^(?:\[?([a-zA-Z][a-zA-Z0-9_]*|[a-zA-Z0-9_]*)\]?)+$/g;
var keys = [];

myInput.replace(regex, function(match,capture,pos,source){
    keys.push(capture);
});

console.log(myInput, keys);

How it fails

My regex is matching only the last "key" E.g.,

# should be ['a', 'b', 'c']
a[b][c]   => ['c']

Tinker on jsFiddle

jsfiddle

3
  • I'm getting ['c'] with your regex against 'a[b][c]'. Commented Dec 6, 2011 at 18:37
  • @MikePartridge I added a jsFiddle link. jsfiddle.net/MVJZc Commented Dec 6, 2011 at 18:38
  • @MikePartridge, I had a false positive result in a different test. You're right, the regex above only captures the last key. (I updated the question) Commented Dec 6, 2011 at 18:39

3 Answers 3

1

I have taken another approach to get the desired results:

  1. Test whether the given phrase is valid.
  2. If valid, use a global match to create an array.

Code: Fiddle: http://jsfiddle.net/MVJZc/2/

///Example
var myInput = "a[b][][c]";

var validate = /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
    pattern = /[a-zA-Z0-9_]+|(?=\[\])/g,
    //(?=\[\]) is used to create an empty entry for []
    keys = null;
if (validate.test(myInput)) {
    keys = myInput.match(pattern);
}

Note: If you want to extend the pattern, e.g. to include the $ character, modify the first RegEx. The second RegEx (pattern) should at least contain all valid characters.

Sign up to request clarification or add additional context in comments.

3 Comments

This is getting close, but some inputs aren't passing. See results here: jsfiddle.net/MVJZc/3
@macek Use my fiddle. My very first answer (which you've used for your fiddle) was missing the + sign at the validate pattern. jsfiddle.net/MVJZc/2
By the way, use /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z][a-zA-Z0-9_]+)\])*$/ if a [...] may only start with a digit if it's only consisting of digits, or /^[a-zA-Z][a-zA-Z0-9_]*(?:\[[a-zA-Z0-9_]+\])*$/ if b[3ab] is also valid.
1

would something like this work?

var input = "a[b][c]";
input = input.replace(/[\[\]]$/,"").replace(/[\]\[]+/g,"|");
var args = input.split("|");

And here's a demo: http://jsfiddle.net/vZBtj/

2 Comments

This does not validate each key. It's only validating the first one. E.g., foo[_invalid] and foo[bar][ fails2] should not return keys.
@macek I see... I would go back and fix it but it seems you found an answer already. :P
0

Here's another possibility, definitely not as succinct as Rob W's, but get's the job done ;-)

function parseThing(aStr){
    var res = [];
    success = false;
    if(aStr.indexOf('[') > 0){
        var idx = aStr.indexOf('[');
        var first = aStr.substring(0, idx);
        if(first.match(/\w/)){
            success = true;
            res.push(first);

            //now parse stuff inside brackets
            var rest = aStr.substring(idx, aStr.length-1);
            var arr = rest.split("]");
            for(i in arr){
                res.push(arr[i].replace("[", ""));
            }
        }
    } else if(aStr.match(/\w/)){
        res.push(aStr);
    }
    return res;
}

console.log(parseThing("a[a][b]"));
console.log(parseThing("a"));
console.log(parseThing("b"));
console.log(parseThing("foo[bar] "));
console.log(parseThing("a[0]"));
console.log(parseThing("b[1]"));
console.log(parseThing("complex[named][0][]"));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.