0

I have a script, which take input from the user and I want to validate the input first then convert the user-input to a predefined format. The input should be like this:

my_script -c 'formatDate(%d/%m) == 23/5 && userName == John Dee && status == c

At the moment I'm dealing with formatDate() bit only. The main rules are:

  • The format string for year,month,day can come in any order
  • if m [or y or d] is missing that will be added using current_month; same for others
  • the same delimiter must be used for the format strings and the values
  • the keys and values must be separated by ==
  • the different constraint must be separated by &&
  • single or multiple constraints are allowed

So, for the given example, it should return 20110523 as a valid constraint. After a bit of work, this is what I come up with, which is pretty much working:

#!/usr/bin/env python
#
import sys, re
from time import localtime, strftime

theDy = strftime('%d', localtime())
theMn = strftime('%m', localtime())
theYr = strftime('%Y', localtime())

def main(arg):

    print "input string: %s" % arg
    arg = "".join(arg.split()).lower()

    if arg.startswith('=') or re.search('===', arg) or "==" not in arg:
       sys.exit("Invalid query string!")
    else: my_arg = arg.split('&&')

    c_dict = {}

    for ix in range(len(my_arg)):
       LL = my_arg[ix].split('==')
       #LL = dict(zip(LL[:-1:2], LL[1::2]))

       # don't add duplicate key
       if not c_dict.has_key(LL[0]):
          c_dict[LL[0]] = LL[1]

       for k,v in sorted(c_dict.items()):
          if k.startswith('formatdate') :
             ymd = re.sub(r'[(,)]', ' ', k).replace('formatdate','')
             ymd = (str(ymd).strip()).split('/')
             if len(ymd) <= 3 and len(ymd) == len(v.split('/')):
                d_dict = dict(zip(ymd, v.split('/')))

                if not d_dict.has_key('%y'):
                   d_dict['%y'] = theYr
                if not d_dict.has_key('%m'):
                   d_dict['%m'] = theMn
                if not d_dict.has_key('%d'):
                   d_dict['%d'] = theDy

             else: sys.exit('date format mismatched!!')

             Y = d_dict['%y'];

             if d_dict['%m'].isdigit() and int(d_dict['%m']) <=12:
                M = d_dict['%m'].zfill(2)
             else: sys.exit("\"Month\" is not numeric or out of range.\nExiting...\n")

             if d_dict['%d'].isdigit() and int(d_dict['%d']) <=31:
                D = d_dict['%d'].zfill(2)
             else: sys.exit("\"Day\" is not numeric or out of range.\nExiting...\n")

             # next line needed for future use  
             fmtFile = re.compile('%s%s%s' % (Y,M,D))
             print "file_name is: %s" % Y+M+D

if __name__ == "__main__":
    main('formatDate(%d/%m)== 23/5')

My questions are:

  • Am I making it unnecessarily complected or expensive? Is there any easier way?
  • How to identify which "delimiter" user has used [as opposed to using a fixed one]?

Thanks for your time. Cheers!!

1 Answer 1

1

You're not making a complication, but have you thought of the consequences of expanding the grammar of the user requests?

The simplest parser is Shunting yard algorithm. You can adopt it to the user requests and expand the grammar easily. You can find Python implementation here.

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

3 Comments

Just another question: Does anyone know how to write a ReExp which will match the only pattern either 20110512 or 20110512-12? For the first one, I just did: re.compile('20/d/d[01]/d[0123]/d$') how to include the second type as well? Cheers!!
Hm, you regex looks wrong to me. To match a date in first format use: (201[0|1])(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]). Btw, try "kodos" program, it's a great tool for testing regexps and it's written in Python+PyQt3.
Yes, of course. I typed the slashes other way round. re.compile('20\d\d[01]\d[0123]\d$') is working just fine. But your one is much more accurate. Cheers!!

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.