views:

142

answers:

4

I'm developing a REST service, so a request could be something like this:

/Data/Main/Table=Customers/

I need to get the segments one by one, and for each segment I will decide wich object I'm going to use, after I'll pass to that object the rest of the query so it can decide what to do next. Basically, the REST query is a path on a tree :P

This imply lots String operations (depending on the query complexity), but StringBuilder is useful just for concatenations and remove, you cannot perform a search with IndexOf or similar.

I've developed this class that fulfill my requirement, but the problem is that is manipulating Strings, so every time I get one segment ... I'll create extra Strings because String is an inmutable data type:

public class RESTQueryParser
{
    String _query;

    public RESTQueryParser(String query)
    {
        _query = query;
    }

    public String GetNext()
    {
        String result = String.Empty;
        Int32 startPosition = _query.StartsWith("/", StringComparison.InvariantCultureIgnoreCase) ? 1 : 0;

        Int32 i = _query.IndexOf("/", startPosition, StringComparison.InvariantCultureIgnoreCase) - 1;

        if (!String.IsNullOrEmpty(_query))
        {
            if (i < 0)
            {
                result = _query.Substring(startPosition, _query.Length - 1);
                _query = String.Empty;
            }
            else
            {
                result = _query.Substring(startPosition, i);
                _query = _query.Remove(0, i + 1);
            }
        }

        return result;
    }
}

The server should support a lot of calls, and the queries could be huge, so this is gonna be a very repetitive task. I don't really know how big is the impact on the memory and the performance, I've just readed about it in some books.

Should I implement a class that manage a Char[] instead Strings and implement the methods that I want? Or should be ok with this one? Regular expressions maybe?

UPDATE:

The above class is just a small aproximation, I'm still working on it and I have to parse more complex patterns.

I cannot use WCF REST or predefined paths (like map a regular expression to a specific method) because the query format can be changed by the user at runtime. So it has to be parsed step by step.

I cannot use String.Split, because for example a query could be : "Data/Search='01/01/2008'/Whatever".

+1  A: 

This problem begs for regular expressions. You should be able to write a concise regular expression to pull out all the groups in that path in one shot. It might or might not be faster, though.

If you haven't measured it, I really doubt that this will be any kind of bottleneck for you. I wouldn't even consider worrying about it unless you expect on the order of thousands of parses per second.

(By the way, I would have to imagine that it would be much, much more pleasant for you to treat your path as an IEnumerable<string>, generating each level of the path in turn, rather than have a class with internal state and a GetNext() method, as you've demonstrated.)

mquander
+8  A: 

Unless you are against using it. I would check here

http://msdn.microsoft.com/en-us/netframework/cc950529.aspx

WCF handles a REST implementation for you. No need to parse out the URL.

If you must parse out the query by hand, I would do use

string[] queryParts = query.Trim('/').Split('/');

You can go through each part individually without having to use IndexOf.

String.Split method: http://msdn.microsoft.com/en-us/library/system.string.split.aspx

If you aren't going to use WCF and it's REST implementation, what you are going to want to do is place your variable information in the query string parameters

/Data/Main/Table=Customers/  

really needs to be:

/Data/Main?Table=Customers

or

/Data/Main/Table/Customers

You are going to need a way to separate the route path from the query variables. The complexity needs to be part of the query string and not part of the base URI. Then you can separate out the variables after the ? and separate out each query expression by splitting on the &.

string[] uriAndQueryItems = query.Split('?');

if(uriAndQueryItems.Length > 1)
{
   foreach(string queryItem in uriAndQueryItems.Split('&'))
   {
    //do something here.
   }
}
Kevin
If you split on '/', by default, you'll have empty entries in your results...
Reed Copsey
@Reed After I hit save I saw yours and realized I missed it. (felt bad copying though).
Kevin
Look what I've updated, it's my bad for not give more details, sorry :P
vtortola
@Kevin: I deleted mine - why don't you add it to yours (although, given the update, it might not matter)
Reed Copsey
+1  A: 

the simple one is string.split - or am i missing something

pm100
+1  A: 

You might try a regular expression like this:

var input = "/Data/Main/Table=Customers/";
var regex = new Regex(@"\w+?/");
var matches = regex.Matches(input);
foreach (var match in matches)
{
    Console.WriteLine(match.ToString());
}
Console.ReadKey();

Also, you might look into the System.Web.Routing namespace...

Todd Sprang