Convert string with engineer prefix to float - python

I have a string like '102.3k' I would like to convert this string with an engineer prefix notation to a float number.
http://en.wikipedia.org/wiki/Engineering_notation
Allowed prefixes are
posPrefixes = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
negPrefixes = ['m', 'µ', 'n', 'p', 'f', 'a', 'z', 'y']
k means 10^3
M means 10^6
m means 10^-3
µ means 10^-6
I think I should use regex to do this but I have very few experience with regex.
edit: ideally the solution should also be able to convert any string so '102.3' (without prefix) should also be converted to float

Try this out, no regex needed:
pos_postfixes = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
neg_postfixes = ['m', 'µ', 'n', 'p', 'f', 'a', 'z', 'y']
num_postfix = n[-1]
if num_postfix in pos_postfixes:
num = float(n[:-1])
num*=10**((pos_postfixes.index(num_postfix)+1)*3)
elif num_postfix in neg_postfixes:
num = float(n[:-1])
num*=10**(-(neg_postfixes.index(num_postfix)+1)*3)
else:
num = float(n)
print(num)
Another thing to note is that in python, it is more common to use underscore variable names than camelcasing, see the pep-8: http://www.python.org/dev/peps/pep-0008/

If you want to control the value, you could try this:
import decimal
posPrefixes = {'k':'10E3', 'M':'10E6', 'G':'10E9', 'T':'10E12', 'P':'10E15', 'E':'10E18', 'Z':'10E21', 'Y':'10E24'}
negPrefixes = {'m':'10E-3', '?':'10E-6', 'n':'10E-9', 'p':'10E-12', 'f':'10E-15', 'a':'10E-18', 'z':'10E-21', 'y':'10E-24'}
val='102.3k'
if val[-1] in posPrefixes.keys():
v = decimal.Decimal(val[:-1])
print v*decimal.Decimal(posPrefixes[val[-1]])
val ='102.3n'
if val[-1] in negPrefixes.keys():
v = decimal.Decimal(val[:-1])
print v*decimal.Decimal(negPrefixes[val[-1]])
Output:
1.0230E+6
1.023e-06

Related

Error, index out of range. What is wrong?

I wrote a Python3 script to solve a picoCTF challenge. I received the encrypted flag which is:
cvpbPGS{c33xno00_1_f33_h_qrnqorrs}
From its pattern, I thought it is encoded using caesar cipher. So I wrote this script:
alpha_lower = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u','v', 'w', 'x', 'y', 'z']
alpha_upper = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
text = 'cvpbPGSc33xno00_1_f33_h_qrnqorrs '
for iterator in range(len(alpha_lower)):
temp = ''
for char in text:
if char.islower():
ind = alpha_lower.index(char)
this = ind + iterator
while this > len(alpha_lower):
this -= len(alpha_lower)
temp += alpha_lower[this]
elif char.isupper():
ind = alpha_upper.index(char)
that = ind + iterator
while that > len(alpha_upper):
that -= len(alpha_upper)
temp += alpha_upper[that]
print(temp)
I understand what the error means. I can't understand where the flaw is to fix. Thanks in advance.
Sorrym here is the error:
Desktop>python this.py
cvpbPGScxnofhqrnqorrs
dwqcQHTdyopgirsorpsst
exrdRIUezpqhjstpsqttu
Traceback (most recent call last):
File "C:\Users\user\Desktop\this.py", line 18, in <module>
temp += alpha_lower[this]
IndexError: list index out of range
Your approach has an error because ind + iterator can have a maximum possible value of 50, which is more than len(alpha_lower)
To fix it, you can use the modulus operator: (ind + iterator) % len(alpha_lower)
There is a less complicated way to decode the Caesar cipher. Instead of using two different lists for upper and lower case characters, you should use the ord() and chr() functions to manipulate the unicode values.
Why that break is simple :
If this==len(alpha_lower) then we won't enter your loop:
while this > len(alpha_lower):
And thus when trying temp += alpha_lower[this] it will return an error.
An index must be strictly inferior to the size of the array. Your condition should have been while this >= len(alpha_lower):.
As pointed out, a better method here is to use a modulus.

Python ignore punctuation and white space

string = "Python, program!"
result = []
for x in string:
if x not in result:
result.append(x)
print(result)
This program makes it so if a repeat letter is used twice in a string, it'll appear only once in the list. In this case, the string "Python, program!" will appear as
['P', 'y', 't', 'h', 'o', 'n', ',', ' ', 'p', 'r', 'g', 'a', 'm', '!']
My question is, how do I make it so the program ignores punctuation such as ". , ; ? ! -", and also white spaces? So the final output would look like this instead:
['P', 'y', 't', 'h', 'o', 'n', 'p', 'r', 'g', 'a', 'm']
Just check if the string (letter) is alphanumeric using str.isalnum as an additional condition before appending the character to the list:
string = "Python, program!"
result = []
for x in string:
if x.isalnum() and x not in result:
result.append(x)
print(result)
Output:
['P', 'y', 't', 'h', 'o', 'n', 'p', 'r', 'g', 'a', 'm']
If you don't want numbers in your output, try str.isalpha() instead (returns True if the character is alphabetic).
You can filler them out using the string module. This build in library contains several constants that refer to collections of characters in order, like letters and whitespace.
import string
start = "Python, program!" #Can't name it string since that's the module's name
result = []
for x in start:
if x not in result and (x in string.ascii_letters):
result.append(x)
print(result)

Python script to generate a word with specific structure and letter combinations

I want to write a really short script that will help me generate a random/nonsense word with the following qualities:
-Has 8 letters
-First letter is "A"
-Second and Fourth letters are random letters
-Fifth letter is a vowel
-Sixth and Seventh letters are random letters and are the same
-Eighth letter is a vowel that's not "a"
This is what I have tried so far (using all the info I could find and understand online)
firsts = 'A'
seconds = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
thirds = ['a', 'e', 'i', 'o', 'u', 'y']
fourths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
fifths = ['a', 'e', 'i', 'o', 'u', 'y']
sixths = sevenths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
eighths = ['e', 'i', 'o', 'u', 'y']
print [''.join(first, second, third, fourth, fifth)
for first in firsts
for second in seconds
for third in thirds
for fourth in fourths
for fifth in fifths
for sixth in sixths
for seventh in sevenths
for eighth in eighths]
However it keeps showing a SyntaxError: invalid syntax after the for and now I have absolutely no idea how to make this work. If possible please look into this for me, thank you so much!
So the magic function you need to know about to pick a random letter is random.choice. You can pass a list into this function and it will give you a random element from that list. It also works with strings because strings are basically a list of chars. Also to make your life easier, use string module. string.ascii_lowercase returns all the letters from a to z in a string so you don't have to type it out. Lastly, you don't use loops to join strings together. Keep it simple. You can just add them together.
import string
from random import choice
first = 'A'
second = choice(string.ascii_lowercase)
third = choice(string.ascii_lowercase)
fourth = choice(string.ascii_lowercase)
fifth = choice("aeiou")
sixthSeventh = choice(string.ascii_lowercase)
eighth = choice("eiou")
word = first + second + third + fourth + fifth + sixthSeventh + sixthSeventh + eighth
print(word)
Try this:
import random
sixth=random.choice(sixths)
s='A'+random.choice(seconds)+random.choice(thirds)+random.choice(fourths)+random.choice(fifths)+sixth+sixth+random.choice(eighths)
print(s)
Output:
Awixonno
Ahiwojjy
etc
There are several things to consider. First, the str.join() method takes in an iterable (e.g. a list), not a bunch of individual elements. Doing
''.join([first, second, third, fourth, fifth])
fixes the program in this respect. If you are using Python 3, print() is a function, and so you should add parentheses around the entire list comprehension.
With the syntax out of the way, let's get to a more interesting problem: Your program constructs every (82255680 !) possible word. This takes a long time and memory. What you want is probably to just pick one. You can of course do this by first constructing all, then picking one at random. It's far cheaper though to pick one letter from each of firsts, seconds, etc. at random and then collecting these. All together then:
import random
firsts = ['A']
seconds = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
thirds = ['a', 'e', 'i', 'o', 'u', 'y']
fourths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
fifths = ['a', 'e', 'i', 'o', 'u', 'y']
sixths = sevenths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
eighths = ['e', 'i', 'o', 'u', 'y']
result = ''.join([
random.choice(firsts),
random.choice(seconds),
random.choice(thirds),
random.choice(fourths),
random.choice(fifths),
random.choice(sixths),
random.choice(sevenths),
random.choice(eighths),
])
print(result)
To improve the code from here, try to:
Find a way to generate the "data" in a neater way than writing it out explicitly. As an example:
import string
seconds = list(string.ascii_lowercase) # you don't even need list()!
Instead of having a separate variable firsts, seconds, etc., collect these into a single variable, e.g. a single list containing each original list as a single str with all characters included.
This will implement what you describe. You can make the code neater by putting the choices into an overall list rather than have several different variables, but you will have to explicitly deal with the fact that the sixth and seventh letters are the same; they will not be guaranteed to be the same simply because there are the same choices available for each of them.
The list choices_list could contain sub-lists per your original code, but as you are choosing single characters it will work equally with strings when using random.choice and this also makes the code a bit neater.
import random
choices_list = [
'A',
'abcdefghijklmnopqrstuvwxyz',
'aeiouy',
'abcdefghijklmnopqrstuvwxyz',
'aeiouy',
'abcdefghijklmnopqrstuvwxyz',
'eiouy'
]
letters = [random.choice(choices) for choices in choices_list]
word = ''.join(letters[:6] + letters[5:]) # here the 6th letter gets repeated
print(word)
Some example outputs:
Alaeovve
Aievellu
Ategiwwo
Aeuzykko
Here's the syntax fix:
print(["".join([first, second, third])
for first in firsts
for second in seconds
for third in thirds])
This method might take up a lot of memory.

Using .join() function on a set incorrectly reorders it [duplicate]

This question already has answers here:
Converting a list to a set changes element order
(16 answers)
Closed 3 years ago.
I have a set of characters (x) that is ordered as I need it:
{'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z'}
However, when I attempt to convert these back to a string using the .join() function:
return ' '.join(x)
The characters are being randomly reordered:
'c g e w i z n t l a q h p d f v m k b x u r j o y'
Any ideas as to what's going on here?
Sets don't "promise" to maintain order, sometimes they do, but they shouldn't be used with a dependency on it. Furthermore, consider using the following:
alpha = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
Then:
return " ".join(alpha)
However, if you only care about it being in alphabetical and want to use a set you can force it to be sorted before using the join function...
return " ".join(sorted(x))
Good luck!
Sets and dictionaries are unordered (pre Python 3.7). Their exact implementation involves hashtables and can be a little complicated. However, suffice it to say that the order you put elements into the set does not determine the order they are stored.
You can use OrderedDict or you can convert the set to a list, sort, and go from there.

Split python list into rows without libraries

I have a list of letters in Python that I would like to split into even-length chunks that will display as rows. For pedagogical reasons, I want to do it without using and libraries (including numpy or Pandas). No, this is not a homework question-- I'm teaching myself.
In R I would be using a vector instead of a list; a simple as.matrix(vector, ncol = n) would do the trick. Is there an equivalent in Python?
As an example, I've tried the following based on other SO answers:
alphabet = map(chr, range(65, 91))
print alphabet
> ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
def chunks(l, n):
n = max(1, n)
return [l[i:i + n] for i in range(0, len(l), n)]
print chunks(alphabet, 4)
> [['A ', 'B', 'C', 'D'], ['E', 'F', 'G', 'H'], ['I', 'J', 'K', 'L'], ['M', 'N', 'O', 'P'], ['Q', 'R', 'S', 'T'], ['U', 'V', 'W', 'X'], ['Y', 'Z']]
That generally works, but I would like the output to look like this:
[['A ', 'B', 'C', 'D'],
['E', 'F', 'G', 'H'],
['I', 'J', 'K', 'L'],
['M', 'N', 'O', 'P'],
['Q', 'R', 'S', 'T'],
['U', 'V', 'W', 'X'],
['Y', 'Z']]
Ideally, I will extend the functionality to make the "most square" rectangle. Ie, I will pull out the highest factors of the length of the list and then use the smaller number as the number of columns, so if possible I want a very generalized answer.
I would define a new function that prints the chunks line by line.
def print_chunks(chunk_result):
for chunk in chunks:
print(chunk)
I believe this will give you the output you're looking for.
To get slicing behaviour, you will want to implement your own class. I have quickly whipped out something that should get you started, but I have not checked it thoroughly.
class Chunk(object):
"""docstring for Chunk"""
def __init__(self, l, n):
super(Chunk, self).__init__()
self.chunks = self.chunk(l, n)
def __repr__(self):
"""
Done in a non-standard way.
"""
for chunk in self.chunks:
print(chunk)
def __getitem__(self, key):
if isinstance(key, slice):
return self.chunks[i] for i in xrange(*key.indices(len(self.chunks)))
elif isinstance(key, int):
if key < 0:
key += len(self.chunks)
if key >= len(self):
raise IndexError('The index {0} is out of range'.format(key))
return self.chunks[i]
For reference, I looked at the following SO posts:
Python: Implementing slicing in __getitem__
Just use print each list within:
for line in chunks(alphabet, 4):
print line

Categories

Resources