re module to convert metric to imperial and vice versa

  • (2 Pages)
  • +
  • 1
  • 2

22 Replies - 1462 Views - Last Post: 24 November 2011 - 07:08 PM Rate Topic: -----

#1 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 02:13 PM


import sys
import re

if len(sys.argv) > 2:
    print "usage: ", sys.argv[0], "type {commandfile}"
    sys.exit(1)

type = sys.argv[1]

if len(sys.argv) == 3:
    cf = open(sys.argv[2], "r")

if len(sys.argv) == 2:
	print ">>>",
	line = raw_input()
else:
	line = cf.readline()
	print ">>> " + line.rstrip()

command = line.split()

feet = r"([+/-]\d\.\d+\s feet)"
f = re.compile(feet)
meters = r"([+/-]\d\.\d+\s metres)"
m = re.compile(meters)
pounds = r"([+/-]\d\.\d+\s pounds)"
p = re.compile(pounds)
kilos = r"([+/-]\d\.\d+\s kilos)"
k = re.compile(kilos)



Im wondering is that right to find the numbers either in a file like
Though Bill weighs 500 pounds and can run
42.3 metres per minute, Sue (who came in at
59 kilos), can outrun him at 910.02 feet
per second, and that while hauling 20.5 kilos
on a braided hemp rope. Amazing! All that
action in 5280 feet!!! Wonder what they could do
in 10000 metres? And Sue with 5.7 pounds?


or in just a single line entry like "600 feet", I'm new to the re module and I'm wondering if each unit i got made is proper
Thanks for your help

Is This A Good Question/Topic? 0
  • +

Replies To: re module to convert metric to imperial and vice versa

#2 Simown  Icon User is offline

  • Blue Sprat
  • member icon

Reputation: 317
  • View blog
  • Posts: 650
  • Joined: 20-May 10

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 02:22 PM

Haven't you tested it to find out? We would be able to give much better advice if you said
"I ran the program and got X and Y, but I was expecting X, Y and Z."

This: http://pythex.appspot.com/ may come in very handy for testing your regex.

This post has been edited by Simown: 24 November 2011 - 02:23 PM

Was This Post Helpful? 1
  • +
  • -

#3 sepp2k  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2013
  • View blog
  • Posts: 3,038
  • Joined: 21-June 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 02:23 PM

The first problem I see is that you're only matching a single digit before the decimal point.

Also "\s " is an arbitrary whitespace character (meaning a tab, a newline, a carriage return or a space) followed by a space. You probably just want "\s" without the " " after it there. Or possibly "\s+".

Oh and the sign should be optional (i.e. followed by a "?"). Also there shouldn't be a slash in there. "[+/-]" means "a plus OR A SLASH or a minus". The slash sign does not mean "or". "|" means or, but only outside of square brackets. Inside square brackets everything is ored by default.
Was This Post Helpful? 1
  • +
  • -

#4 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 02:27 PM

This is what I got now

feet = r"([+-]?\d+\.\d+ feet)"
meters = r"([+-]?\d+\.\d+ metres)"
pounds = r"([+-]?\d+\.\d+ pounds)"
kilos = r"([+-]?\d+\.\d+ kilos)"



would this be good for something like
"660 feet"
"220.7 metres"
"3 pounds" ????

This post has been edited by labradorguy: 24 November 2011 - 02:29 PM

Was This Post Helpful? 0
  • +
  • -

#5 sepp2k  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2013
  • View blog
  • Posts: 3,038
  • Joined: 21-June 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 02:32 PM

Well, as Simown said, the surest way to find out is to just test it. But from looking at it, it looks okay. The surrounding parentheses are probably unnecessary though (unless you absolutely need a capturing group containing everything).

Now that I think about it, it would probably be useful to have parentheses around the numeric part (i.e. without the space and the unit), but that depends on how you'll use your regexes of course.
Was This Post Helpful? 0
  • +
  • -

#6 Simown  Icon User is offline

  • Blue Sprat
  • member icon

Reputation: 317
  • View blog
  • Posts: 650
  • Joined: 20-May 10

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 02:48 PM

It won't work like that, look at this part:

\d\.\d+


This captures 1 digit, followed by a decimal point, followed by one or more digits. So, it will capture 600.0, but not 600 or 600. even.

You want to use "?" for "1 or not at all", "*" for "0 or more times" and "+" for "1 or more times"

\d+\.?\d*


This will now capture 1 or more digits possibly followed by a decimal point, followed by 0 or more digits. So, it will match for example: 490, 490.0, 4900.0000 etc.

This post has been edited by Simown: 24 November 2011 - 02:56 PM

Was This Post Helpful? 1
  • +
  • -

#7 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 03:37 PM

This is what I got now, but I don't know how to convert the numbers, I keep getting this error
"invalid literal for int() with base 10: '\\d+\\.?\\d+'"

import sys
import re

if len(sys.argv) > 2:
    print "usage: ", sys.argv[0], "type {commandfile}"
    sys.exit(1)

type = sys.argv[1]

if len(sys.argv) == 3:
    cf = open(sys.argv[2], "r")
	
text = {}

if len(sys.argv) == 2:
	print ">>>",
	line = raw_input()
else:
	line = cf.readline()
	print ">>> " + line.rstrip()

command = line.split()

feet = "(\d+\.?\d+ feet)"
f = re.compile(feet)
metres = "(\d+\.?\d+ metres)"
m = re.compile(metres)
pounds = "(\d+\.?\d+ metres)"
p = re.compile(pounds)
kilos = "(\d+\.?\d+ metres)"
k = re.compile(kilos)

if( type == "Metric"):
	for x in line:
		re.sub(f, int("\d+\.?\d+")*0.305, line)
		re.sub(p, int("\d+\.?\d+")*0.454, line)
		


Was This Post Helpful? 0
  • +
  • -

#8 sepp2k  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2013
  • View blog
  • Posts: 3,038
  • Joined: 21-June 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 03:46 PM

In order to make re.sub perform a calculation for each match, you need to pass a function as the second argument. The function should take a match object containing information about the match (like the contents of its capturing groups) and return the string that the match should be replaced with.

If you follow my advice of putting the numeric part into a capturing group (by surrounding it with parentheses instead of surrounding the whole pattern), you can then simply get the numeric part from the match object and pass it to int() in the function you pass to re.sub.

PS: The way your regex looks now it will not accept single digit numbers (because both "\d+"s need to match at least once). If you don't want to match things like "6.", the correct way to achieve this would be "\d+(?:\.\d+)?", i.e. make both the decimal point and the digits after the decimal point optional).
Was This Post Helpful? 0
  • +
  • -

#9 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 03:55 PM

feet = ("\d*\.?\d+" " feet")



thank you for catching that, i changed the + to * and that will make it so 0 or more vs 1 or more so if i am correct that should fix the single digit problem.

But i am still having trouble understanding how to get the numeric section and put it in a function, I put the numeric area between parenthesis like you suggested but I don't understand why I did that.

Thank you in advance you have been a huge help

This post has been edited by labradorguy: 24 November 2011 - 04:00 PM

Was This Post Helpful? 0
  • +
  • -

#10 Simown  Icon User is offline

  • Blue Sprat
  • member icon

Reputation: 317
  • View blog
  • Posts: 650
  • Joined: 20-May 10

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 03:57 PM

You don't want to convert just the regex to an int, you want the whole result you have already compiled the pattern, so use it:

for match in re.findall(pattern, string):
           string.replace(match, str(int(match)*0.305))



You need to convert it back to a string to replace it back in the string.

This post has been edited by Simown: 24 November 2011 - 04:04 PM

Was This Post Helpful? 0
  • +
  • -

#11 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 04:09 PM

if i do it with the find all I still get the same error "invalid literal for int() with base 10: '600 feet'"
Was This Post Helpful? 0
  • +
  • -

#12 Simown  Icon User is offline

  • Blue Sprat
  • member icon

Reputation: 317
  • View blog
  • Posts: 650
  • Joined: 20-May 10

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 04:11 PM

You can't convert "600 feet" to an integer. You'll have to replace "feet" and the number separately.

For example:
string.replace(match, str(int(match)*0.305))
string.replace("feet", "meters")


Was This Post Helpful? 0
  • +
  • -

#13 sepp2k  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2013
  • View blog
  • Posts: 3,038
  • Joined: 21-June 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 04:40 PM

@Simown: I don't really see why using find_all and calling replace in a loop is preferable to passing a function to sub. I'd still go with the latter.

@labradorguy: You get the numeric part by surrounding the part of the regex which matches the number (i.e. the "\d+\.?\d*" part) with parentheses instead of surrounding the whole pattern. Then you can call group(1) on a match object to get the numeric part. On that you can call int.
Was This Post Helpful? 0
  • +
  • -

#14 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 04:47 PM

 
if len(sys.argv) > 2:
    print "usage: ", sys.argv[0], "type {commandfile}"
    sys.exit(1)

type = sys.argv[1]

if len(sys.argv) == 3:
    cf = open(sys.argv[2], "r")
	

if len(sys.argv) == 2:
	print ">>>",
	line = raw_input()
else:
	line = cf.readlines()
	print ">>> " + line.rstrip()

command = line.split()

feet = ("\d*\.?\d+" " feet")
f = re.compile(feet)
metres = ("\d*\.?\d+" " metres")
m = re.compile(metres)
pounds = ("\d*\.?\d+" " metres")
p = re.compile(pounds)
kilos = ("\d*\.?\d+" " metres")
k = re.compile(kilos)

if( type == "Metric"):
	for match in re.findall(f, line):
		line.replace(match, str(int(match)*.305))
		line.replace("feet", "meters")
	for match in re.findall(p, line):
		line.replace(match, str(int(match)*.454))
		line.replace("pounds", "kilos")

elif( type == "Imperial"):
	for match in re.findall(k, line):
		line.replace(match, str(int(match)*2.202))
		line.replace("kilos", "pounds")



I know the problem is that is still trying to convert "600 feet" but how do i split it up to read 600 and feet as two different string thank you
for match in re.findall(m, line):
line.replace(match, str(int(match)*3.28))
line.replace("metres", "feet")
Was This Post Helpful? 0
  • +
  • -

#15 labradorguy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 41
  • Joined: 25-July 11

Re: re module to convert metric to imperial and vice versa

Posted 24 November 2011 - 05:04 PM

import sys
import re

def changetometres(m):
	number = m.group(1)
	number1 = int(number)*0.305
	return number1
	
def changetokilos(m):
	number = m.group(1)
	number1 = int(number)*0.454
	return number1
	
def changetopounds(m):
	number = m.group(1)
	number1 = int(number)*2.202
	return number1
	
def changetofeet(m):
	number = m.group(1)
	number1 = int(number)*3.28
	return number1


if len(sys.argv) > 2:
    print "usage: ", sys.argv[0], "type {commandfile}"
    sys.exit(1)

type = sys.argv[1]

if len(sys.argv) == 3:
    cf = open(sys.argv[2], "r")
	

if len(sys.argv) == 2:
	print ">>>",
	line = raw_input()
else:
	line = cf.readlines()
	print ">>> " + line.rstrip()

command = line.split()

feet = ("\d*\.?\d+" " feet")
f = re.compile(feet)
metres = ("\d*\.?\d+" " metres")
m = re.compile(metres)
pounds = ("\d*\.?\d+" " metres")
p = re.compile(pounds)
kilos = ("\d*\.?\d+" " metres")
k = re.compile(kilos)

""""if( type == "Metric"):
	for match in re.findall(f, line):
		number = "\d*\.?\d+"
		line.replace(match, str(int(number)*.305))
		line.replace("feet", "meters")
	for match in re.findall(p, line):
		line.replace(match, str(int(match)*.454))
		line.replace("pounds", "kilos")

elif( type == "Imperial"):
	for match in re.findall(k, line):
		line.replace(match, str(int(match)*2.202))
		line.replace("kilos", "pounds")
		
	for match in re.findall(m, line):
		line.replace(match, str(int(match)*3.28))
		line.replace("metres", "feet")"""
		
if( type == "Metric"):
	for x in line:
	    re.sub(f, changetometres(f), line)
        re.sub(p, changetokilos(p), line)

if( type == "Imperial"):
	for x in line:
	    re.sub(m, changetofeet(m), line)
        re.sub(k, changetopounds(k), line)		
		



When I do it the function way I get an error that just says "AttributeError: group"

And when I do it the finad all way I still get "invalid literal for int() with base 10: '600 feet'"
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2