1

I have a String that contains the following:

?workarea=London+&+Home+Counties+Ltd&sub=fs&&&FASh*5

which resembles a URI query string. What is the best way to parse the elements of this string (workarea and sub) without messing about with string manipulation?

If I use HttpUtility.ParseQueryString is gets stuck as both elements include &. However if I encode the whole thing first I lose the seperations of the elements. Ideally the output would be:

  • workarea = London & Home Counties Ltd
  • sub = fs&&&FASh*5
10
  • 1
    Just use Server.URLEncode to encode each value.. Commented Jan 10, 2011 at 11:53
  • Thats what I'm looking to do - but I need to separate said values first Commented Jan 10, 2011 at 11:56
  • ParseQueryString is the best option. ?name=black&white is valid, but doesn't mean what you want it to mean. Also, + for spaces are grossly outdated. Where did you get this string? Commented Jan 10, 2011 at 12:00
  • 1
    @Kobi - I disagree, google uses the + for spaces Commented Jan 10, 2011 at 12:01
  • Does this mean that you have no control over the original string because I think that is where your problem lies. Commented Jan 10, 2011 at 12:02

4 Answers 4

2

You can use this custom function... quick test show that with the string you originally gave in the question it returns the desired output which is two items, one with key sub and value fs&&&FASh*5 and another with key workarea and value London+&Home+Counties+Ltd.

public Dictionary<string, string> ParseQueryString(string qs)
{
    Dictionary<string, string> items = new Dictionary<string, string>();
    string valueBuffer = string.Empty;
    string keyBuffer = string.Empty;
    bool lookingForValue = true;
    for (int i = qs.Length - 1; i >= 0; i--)
    {
        char curChar = qs[i];
        if (curChar.Equals('='))
        {
            lookingForValue = false;
            keyBuffer = string.Empty;
        }
        else if (curChar.Equals('&') && !lookingForValue)
        {
            items.Add(keyBuffer, valueBuffer);
            valueBuffer = string.Empty;
            lookingForValue = true;
        }
        else if (curChar.Equals('?'))
        {
            if (keyBuffer.Length > 0)
                items.Add(keyBuffer, valueBuffer);
            break;
        }
        else
        {
            if (lookingForValue)
                valueBuffer = curChar + valueBuffer;
            else
                keyBuffer = curChar + keyBuffer;
        }
    }

    return items;
}

As I told in the comment, if used for real querystring use Server.URLEncode to encode each value.

Quick explanation: instead of parsing the query string according to & which can't be done, it's looking for = characters, when found start looking for & that appear before.

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

2 Comments

Nice solution. I just hope there is no possibility for & in the keys too. :)
@Chris lol that will be way too much.. and render this whole thing with big red Impossible flag. ;-)
0

I think you need to do some encoding... You seem to want & to be used as both a delimiter and as data without needing to be escaped. A simple parser will not be able to tell which usage you mean (as when you tried the ParseQueryString method).

If you know what your possible element names are (eg workarea, sub) then you could use that to more accurately determine which & are delimiters and which are data by assuing that any & followed by a element name is a delimiter and any others aren't. I think this is getting into the realms of "messing about with string manipulation" though...

My first course of action though would be to change what my input string was if possible to make it more well defined and less ambiguous.

1 Comment

I agree with this, make the input string less ambiguous
0

This can be a good use of a regular expression. Of course, this depends on your exact definition, but here's what I took:

  • A key cannot contain & or = - otherwise you have ambiguity.
  • Values cannot contain = - we may be able to work around that one, but it's much simpler this way.
  • A value will be matched until the end of the string, or until there's one more ampersand. If you have multiple ampersands on the end of the value, this should work well: a=12&&&&b=3 -> a=12&&&, b=3

Here's the code:

MatchCollection parameters = Regex.Matches(query, "([^?&=]+)=([^=]+)(?=&|$)");

Now you have a collection of key and values, where on each Match the second Group is the key (index 1), and the third is the value (index 2).
For example, you may convert the matches to a dictionary (if you don't have any duplicated keys):

var values = parameters.Cast<Match>()
                .ToDictionary(m => m.Groups[1].Value,
                              m => HttpUtility.UrlDecode(m.Groups[2].Value),
                              StringComparer.OrdinalIgnoreCase);
string workAread = values["workarea"];

Comments

-1

I happened to write a blog post about this recently that also contains a small utility class for manipulating query string params. Here's some example usage cases (taken from my post):

QueryStringHelper qsh = new QueryStringHelper("?page=5&username=dan&year=2010&enabled=true&[email protected]");

string username = qsh.GetByName("username"); // username = "dan"

qsh.Add("category", "products"); // adds a new key called "category" with the value "products"

qsh.AddOrReplace("year", "1999"); // changes the year value from "2010" to "1999"

int year = qsh.GetByName<int>("year"); // year = 1999

qsh.AddOrReplace("page", 6); // changes the value of "page" to "6"

bool enabled = qsh.GetByName<bool>("enabled"); // enabled = true

qsh.RemoveByName("email"); // removes the "email" key

string qs = qsh.GetQueryString(); // qs = "page=6&username=dan&year=1999&enabled=true&category=products";

int count = qsh.Count(); // count = 5

I hope you find it of use.

2 Comments

Does this actually deal with the original problem of & as data as opposed to delimiters? I haven't looked at your QSH class but I'd imagine if it is aimed at querystrings it will assume that all & are delimiters.
@Chris - You are correct. I obviously didn't read the question correctly.

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.