How to convert dec to hex in python? - python

When I try to convert big numbers I get extra numbers at the end that doesn't move plus an L character too. How to remove the 4 extra characters at the end 000L?
8b8dbbc584d9c000L
8b8dc4ddd34c6000L
8b8dcdf621bf0000L
8b8dd70e7031a000L
8b8de026bea44000L
#!/usr/bin/python
import sys
def int_tuple_from_cmdline():
"""return exactly two integers form sys.argv
or die with an error message
"""
import sys
args = sys.argv[1:] # drop first entry (progpath)
if len(args) != 2:
raise SystemExit("\n#################################################\n# Please enter both a
start and stop parameter. #\n#################################################")
for i in range(len(args)):
try:
args[i] = int(args[i])
except ValueError:
raise SystemExit("\n#################################################\n# Parameter %d is not an integer. You entered: %s #\n#################################################\n" %(i+1,args[i]))
return tuple(args)
start, stop = int_tuple_from_cmdline()
r = start - 10000000000000
while r < stop:
r = r + 50000000000000
hx = hex(r)[2:]
print(hx)

If what you're after is simply removing the last four characters of a string, you can use slicing to perform it:
s = "8b8dbbc584d9c000L"
trimmed = s[:-4] #8b8dbbc584d9c
Note that it will produce an empty string if the original string doesn't have at least four characters.
Also note that my answer has nothing to do with conversion from decimal to hex per se, I'm just answering the trimming part of it.

Related

ValueError: could not convert string to float: '$50.50'

I have this python function here. However when running I'm getting an error "could not convert string to float: '$50.50'". I need to add the input as a string including the "$" sign and then convert it to a float number in the backend. The function seems to work adding only "50.50" as input.
def main():
dollars = dollars_to_float(input("How much was the meal? "))
percent = percent_to_float(input("What percentage would you like to tip? "))
tip = dollars * percent/100
print(f"Leave $" , str(tip) )
def dollars_to_float(d):
str.lstrip(d)
return float(d)
def percent_to_float(p):
str.rstrip(p)
return float(p)
main()
Error:
File "/Users/nelsonlamounier/indoor/indoor.py", line 13, in <module>
main()
File "/Users/nelsonlamounier/indoor/indoor.py", line 9, in dollars_to_float
return float(d)
File "/Users/nelsonlamounier/indoor/indoor.py", line 9, in dollars_to_float
return float(d)
ValueError: could not convert string to float: '$50.50'
For a more general case, update dollars_to_float with the following:
def dollars_to_float(d):
d = ''.join([ch for ch in d if ch.isnumeric() or ch == '.'])
return float(d)
Just remove $ before number like:
def dollars_to_float(d):
str.lstrip(d)
return float(d.replace("$",""))
Your code is error prone, as a single space character would already be able to break it. A more robust version of the currency to float conversion can be found here Remove currency symbols and literals from a string with a price universal solution
You use locale to see what is the decimal point character (, or .), and regex to remove all characters other than numerals and the decimal point.
import re
import locale
def dollars_to_float(price_string: str) -> float:
decimal_point_char = locale.localeconv()['decimal_point']
clean = re.sub(r'[^0-9'+decimal_point_char+r']+', '', str(price_string))
return float(clean)
If you want to remove specific characters from the beginning or end of a string then use strip()
In this case your dollars_to_float and percent_to_float could be generalised to:
def to_float(d):
return float(d.strip('$%'))
This has the advantage of supporting the $ and % characters at either the beginning or end of the string.
However, say the input is like this '$1,200'
That's going to fail due to the thousands separator. Also, why limit functionality to just dollars. Why not allow for an arbitrary preamble to the input string - e.g., USD1,200 or £1,234,50
Here's a reasonably robust approach to this problem.
import re
from locale import LC_NUMERIC, setlocale, localeconv
class CC:
dp = None
def __init__(self):
if CC.dp is None:
setlocale(LC_NUMERIC, '')
dp = localeconv()['decimal_point']
CC.dp = f'[^0-9{dp}+-]+'
def conv(self, s):
return float(re.sub(CC.dp, '', s))
print(CC().conv('$1,200.5'))
print(CC().conv('£1,200'))
print(CC().conv('EUR1234.5'))
print(CC().conv('6543.21'))
Output:
1200.5
1200.0
1234.5
6543.21

How to overcome a ValueError when working with multiple if conditions?

I'm trying to make a script that can identify if a folder name is a project or not. To do this I want to use multiple if conditions. But I struggle with the resulting ValueError that comes from checking, for example, the first letter of a folder name and if it is a Number. If it's a String i want to skip the folder and make it check the next one. Thank you all in advance for your help.
Cheers, Benn
I tried While and except ValueError: but haven't been successful with it.
# Correct name to a project "YYMM_ProjectName" = "1908_Sample_Project"
projectnames = ['190511_Waldfee', 'Mountain_Shooting_Test', '1806_Coffe_Prime_Now', '180410_Fotos', '191110', '1901_Rollercoaster_Vision_Ride', 'Musicvideo_LA', '1_Project_Win', '19_Wrong_Project', '1903_di_2', '1907_DL_2', '3401_CAR_Wagon']
# Check conditions
for projectname in projectnames:
if int(str(projectname[0])) < 3 and int(projectname[1]) > 5 and ((int(projectname[2]) * 10) + int(projectname[3])) <= 12 and str(projectname[4]) == "_" and projectname[5].isupper():
print('Real Project')
print('%s is a real Project' % projectname)
# print("Skipped Folders")
ValueError: invalid literal for int() with base 10: 'E'
From what I understand from all the ifs...you may actually be better off using a regex match. You're parsing through each character, and expecting each individual one to be within a very limited character range.
I haven't tested this pattern string, so it may be incorrect or need to be tweaked for your needs.
import re
projectnames = ['1911_Waldfee', "1908_Project_Test", "1912_WinterProject", "1702_Stockfootage", "1805_Branded_Content"]
p = ''.join(["^", # Start of string being matched
"[0-2]", # First character a number 0 through 2 (less than 3)
"[6-9]", # Second character a number 6 through 9 (single digit greater than 5)
"(0(?=[0-9])|1(?=[0-2]))", # (lookahead) A 0 followed only by any number 0 through 9 **OR** A 1 followed only by any number 0 through 2
"((?<=0)[1-9]|(?<=1)[0-2])", # (lookbehind) Match 1-9 if the preceding character was a 0, match 0-2 if the preceding was a 1
"_", # Next char is a "_"
"[A-Z]", #Next char (only) is an upper A through Z
".*$" # Match anything until end of string
])
for projectname in projectnames:
if re.match(p, projectname):
#print('Real Project')
print('%s is a real Project' % projectname)
# print("Skipped Folders")
EDIT: ========================
You can step-by-step test the pattern using the following...
projectname = "2612_UPPER"
p = "^[0-2].*$" # The first character is between 0 through 2, and anything else afterwards
if re.match(p, projectname): print(projectname)
# If you get a print, the first character match is right.
# Now do the next
p = "^[0-2][6-9].*$" # The first character is between 0 through 2, the second between 6 and 9, and anything else afterwards
if re.match(p, projectname): print(projectname)
# If you get a print, the first and second character match is right.
# continue with the third, fourth, etc.
This is something that just gets the work done and may not be the most efficient way to do this.
Given your list of projects,
projectnames = [
'190511_Waldfee',
'Mountain_Shooting_Test',
'1806_Coffe_Prime_Now',
'180410_Fotos',
'191110',
'1901_Rollercoaster_Vision_Ride',
'Musicvideo_LA',
'1_Project_Win',
'19_Wrong_Project',
'1903_di_2',
'1907_DL_2',
'3401_CAR_Wagon'
]
I see that there are a limited number of valid YYMM strings (24 of them to be more precise). So I first create a list of these 24 valid YYMMs.
nineteen = list(range(1900, 1913))
eighteen = list(range(1800, 1813))
YYMM = nineteen + eighteen # A list of all 24 valid dates
Then I modify your for loop a little bit using a try-except-else block,
for projectname in projectnames:
try:
first_4_digits = int(projectname[:4]) # Make sure the first 4 are digits.
except ValueError:
pass # Pass silently
else:
if (first_4_digits in YYMM
and projectname[4] == "_"
and projectname[5].isupper()):
# if all conditions are true
print("%s is a real project." % projectname)
One solution would be to make a quick function that catches an error and returns false:
def isInt(elem):
try:
int(elem)
return True
except ValueError:
return False
...
if all(isInt(e) for e in projectname[:3]) and int(str(projectname[0])) < 3 and ...:
...
Or you could use something like str.isdigit() as a check first, rather than writing your own function, to avoid triggering the ValueError in the first place.
Though if I were you I would reconsider why you need such a long and verbose if statement in the first place. There might be a more efficient way to implement this feature.
You could write a small parser (might be a bit over the top, admittedly):
from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
from parsimonious.exceptions import ParseError
projectnames = ['190511_Waldfee', 'Mountain_Shooting_Test', '1806_Coffe_Prime_Now', '180410_Fotos', '191110', '1901_Rollercoaster_Vision_Ride', 'Musicvideo_LA', '1_Project_Win', '19_Wrong_Project', '1903_di_2', '1907_DL_2', '3401_CAR_Wagon']
class ProjectVisitor(NodeVisitor):
grammar = Grammar(
r"""
expr = first second third fourth fifth rest
first = ~"[0-2]"
second = ~"[6-9]"
third = ~"\d{2}"
fourth = "_"
fifth = ~"[A-Z]"
rest = ~".*"
"""
)
def generic_visit(self, node, visited_children):
return visited_children or node
def visit_third(self, node, visited_children):
x, y = int(node.text[0]), int(node.text[1])
if not (x * 10 + y) <= 12:
raise ParseError
# loop over them
pv = ProjectVisitor()
for projectname in projectnames:
try:
pv.parse(projectname)
print("Valid project name: {}".format(projectname))
except ParseError:
pass
This yields
Valid project name: 1806_Coffe_Prime_Now
Valid project name: 1901_Rollercoaster_Vision_Ride
Valid project name: 1907_DL_2

Given a string, how do I check if it is a float?

I have to use python to read a file, this file contains combination of characters, numbers and other stuff.
After reading a single line from the file, how do I check if this line is an integer or a float? (I have to know this information that this line is an integer and float)
I have tried these string methods .isdigit(), .isdecimal(), .isnumeric(), it seems like these methods only return True when there are only all decimal numbers within the string.
Is there any method that can help me to do this task?
P.S.: Can't use try or any exception approach.
============== Content of my File =================
0
[Begin Description]
xxx
[End Description]
1.1
[Begin Description]
....
I want to know if the current line I am reading is integer 0 or float 1.1. That makes my question.
I hope this will help
import re
s = "1236.0"
r = re.compile(r'[1-9]')
r2 = re.compile(r'(\.)')
if re.search(r,s) and re.search(r2,s):
print("Float")
if re.search(r,s) and not re.search(r2,s):
print("Integer")
You should use try and except:
But if you dont want to use it and need different way then use regex:
if re.match(r"[-+]?\d+(\.0*)?$", s):
print("match")
For each line in the file you can check with regex whether it is a float or int or normal string
import re
float_match = re.compile("^[-+]?[0-9]*[.][0-9]+$")
int_match = re.compile("^[-+]?[0-9]+$")
lines = ["\t23\n", "24.5", "-23", "0.23", "-23.56", ".89", "-122", "-abc.cb"]
for line in lines:
line = line.strip()
if int_match.match(line):
print("int")
elif float_match.match(line):
print("float")
else:
print("str")
Result:
int
float
int
float
float
float
int
str
How it works:
int_match = re.compile("^[-+]?[0-9]+$")
^: at the str beginning
[-+]?: optional + or -
[0-9]+: one or more numbers
$: end of string
float_match = re.compile("^[-+]?[0-9]*[.][0-9]+$")
^[-+]?: start with either + or - optional.
[0-9]*: any number of digits or none.
[.]: dot
[0-9]+: one or more digits
$:end
This is faster than re
although this is not type checking but as you are reading string 0 or 1.1 you can do simply like
line='1.1'
if '.' in line:
print("float")
else:
print("int")
Try this :
import re
line1 = '0'
line2 = 'description one'
line3 = '1.1'
line4 = 'begin description'
lines = [line1, line2, line3, line4] # with readlines() you can get it directly
for i in lines:
if re.findall("[+-]?\d+", i) and not re.findall("[+-]?\d+\.\d+", i):
print('int found')
elif re.findall("[+-]?\d+\.\d+", i):
print('float found')
else:
print('no numeric found')
OUTPUT :
int found
no numeric found
float found
no numeric found
You could split it into words using .split() and use string methods.
Example Code (Note that split method argument should be changed to comma if you use it in floats instead of dot):
def float_checker(strinput):
digit_res = None
for part in strinput.split('.'):
digit_res = True if part.isnumeric() else False
if digit_res:
return True
return False
if __name__ == '__main__':
while True:
print(float_checker(input('Input for float check (Stop with CTRL+C): ')))

Read Null terminated string in python

I'm trying to read a null terminated string but i'm having issues when unpacking a char and putting it together with a string.
This is the code:
def readString(f):
str = ''
while True:
char = readChar(f)
str = str.join(char)
if (hex(ord(char))) == '0x0':
break
return str
def readChar(f):
char = unpack('c',f.read(1))[0]
return char
Now this is giving me this error:
TypeError: sequence item 0: expected str instance, int found
I'm also trying the following:
char = unpack('c',f.read(1)).decode("ascii")
But it throws me:
AttributeError: 'tuple' object has no attribute 'decode'
I don't even know how to read the chars and add it to the string, Is there any proper way to do this?
Here's a version that (ab)uses __iter__'s lesser-known "sentinel" argument:
with open('file.txt', 'rb') as f:
val = ''.join(iter(lambda: f.read(1).decode('ascii'), '\x00'))
How about:
myString = myNullTerminatedString.split("\x00")[0]
For example:
myNullTerminatedString = "hello world\x00\x00\x00\x00\x00\x00"
myString = myNullTerminatedString.split("\x00")[0]
print(myString) # "hello world"
This works by splitting the string on the null character. Since the string should terminate at the first null character, we simply grab the first item in the list after splitting. split will return a list of one item if the delimiter doesn't exist, so it still works even if there's no null terminator at all.
It also will work with byte strings:
myByteString = b'hello world\x00'
myStr = myByteString.split(b'\x00')[0].decode('ascii') # "hello world" as normal string
If you're reading from a file, you can do a relatively larger read - estimate how much you'll need to read to find your null string. This is a lot faster than reading byte-by-byte. For example:
resultingStr = ''
while True:
buf = f.read(512)
resultingStr += buf
if len(buf)==0: break
if (b"\x00" in resultingStr):
extraBytes = resultingStr.index(b"\x00")
resultingStr = resultingStr.split(b"\x00")[0]
break
# now "resultingStr" contains the string
f.seek(0 - extraBytes,1) # seek backwards by the number of bytes, now the pointer will be on the null byte in the file
# or f.seek(1 - extraBytes,1) to skip the null byte in the file
(edit version 2, added extra way at the end)
Maybe there are some libraries out there that can help you with this, but as I don't know about them lets attack the problem at hand with what we know.
In python 2 bytes and string are basically the same thing, that change in python 3 where string is what in py2 is unicode and bytes is its own separate type, which mean that you don't need to define a read char if you are in py2 as no extra work is required, so I don't think you need that unpack function for this particular case, with that in mind lets define the new readString
def readString(myfile):
chars = []
while True:
c = myfile.read(1)
if c == chr(0):
return "".join(chars)
chars.append(c)
just like with your code I read a character one at the time but I instead save them in a list, the reason is that string are immutable so doing str+=char result in unnecessary copies; and when I find the null character return the join string. And chr is the inverse of ord, it will give you the character given its ascii value. This will exclude the null character, if its needed just move the appending...
Now lets test it with your sample file
for instance lets try to read "Sword_Wea_Dummy" from it
with open("sword.blendscn","rb") as archi:
#lets simulate that some prior processing was made by
#moving the pointer of the file
archi.seek(6)
string=readString(archi)
print "string repr:", repr(string)
print "string:", string
print ""
#and the rest of the file is there waiting to be processed
print "rest of the file: ", repr(archi.read())
and this is the output
string repr: 'Sword_Wea_Dummy'
string: Sword_Wea_Dummy
rest of the file: '\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6=\x00\x00\x00\x00\xeaQ8?\x9e\x8d\x874$-i\xb3\x00\x00\x00\x00\x9b\xc6\xaa2K\x15\xc6=;\xa66?\x00\x00\x00\x00\xb8\x88\xbf#\x0e\xf3\xb1#ITuB\x00\x00\x80?\xcd\xcc\xcc=\x00\x00\x00\x00\xcd\xccL>'
other tests
>>> with open("sword.blendscn","rb") as archi:
print readString(archi)
print readString(archi)
print readString(archi)
sword
Sword_Wea_Dummy
ÍÌÌ=p=Š4:¦6¿JÆ=
>>> with open("sword.blendscn","rb") as archi:
print repr(readString(archi))
print repr(readString(archi))
print repr(readString(archi))
'sword'
'Sword_Wea_Dummy'
'\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6='
>>>
Now that I think about it, you mention that the data portion is of fixed size, if that is true for all files and the structure on all of them is as follow
[unknow size data][know size data]
then that is a pattern we can exploit, we only need to know the size of the file and we can get both part smoothly as follow
import os
def getDataPair(filename,knowSize):
size = os.path.getsize(filename)
with open(filename, "rb") as archi:
unknown = archi.read(size-knowSize)
know = archi.read()
return unknown, know
and by knowing the size of the data portion, its use is simple (which I get by playing with the prior example)
>>> strins_data, data = getDataPair("sword.blendscn", 80)
>>> string_data, data = getDataPair("sword.blendscn", 80)
>>> string_data
'sword\x00Sword_Wea_Dummy\x00'
>>> data
'\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6=\x00\x00\x00\x00\xeaQ8?\x9e\x8d\x874$-i\xb3\x00\x00\x00\x00\x9b\xc6\xaa2K\x15\xc6=;\xa66?\x00\x00\x00\x00\xb8\x88\xbf#\x0e\xf3\xb1#ITuB\x00\x00\x80?\xcd\xcc\xcc=\x00\x00\x00\x00\xcd\xccL>'
>>> string_data.split(chr(0))
['sword', 'Sword_Wea_Dummy', '']
>>>
Now to get each string a simple split will suffice and you can pass the rest of the file contained in data to the appropriated function to be processed
Doing file I/O one character at a time is horribly slow.
Instead use readline0, now on pypi: https://pypi.org/project/readline0/ . Or something like it.
In 3.x, there's a "newline" argument to open, but it doesn't appear to be as flexible as readline0.
Here is my implementation:
import struct
def read_null_str(f):
r_str = ""
while 1:
back_offset = f.tell()
try:
r_char = struct.unpack("c", f.read(1))[0].decode("utf8")
except:
f.seek(back_offset)
temp_char = struct.unpack("<H", f.read(2))[0]
r_char = chr(temp_char)
if ord(r_char) == 0:
return r_str
else:
r_str += r_char

Python - Concatenate a variable into string format

I'm trying to retrieve the number from a file, and determine the padding of it, so I can apply it to the new file name, but with an added number. I'm basically trying to do a file saver sequencer.
Ex.:
fileName_0026
0026 = 4 digits
add 1 to the current number and keep the same amount of digit
The result should be 0027 and on.
What I'm trying to do is retrieve the padding number from the file and use the '%04d'%27 string formatting. I've tried everything I know (my knowledge is very limited), but nothing works. I've looked everywhere to no avail.
What I'm trying to do is something like this:
O=fileName_0026
P=Retrieved padding from original file (4)
CN=retrieve current file number (26)
NN=add 1 to current file number (27)
'%0 P d' % NN
Result=fileName_0027
I hope this is clear enough, I'm having a hard time trying to articulate this.
Thanks in advance for any help.
Cheers!
There's a few things going on here, so here's my approach and a few comments.
def get_next_filename(existing_filename):
prefix = existing_filename.split("_")[0] # get string prior to _
int_string = existing_filename.split("_")[-1].split(".")[0] # pull out the number as a string so we can extract an integer value as well as the number of characters
try:
extension = existing_filename.split("_")[-1].split(".")[-1] # check for extension
except:
extension = None
int_current = int(int_string) # integer value of current filename
int_new = int(int_string) + 1 # integer value of new filename
digits = len(int_string) # number of characters/padding in name
formatter = "%0"+str(digits)+"d" # creates a statement that int_string_new can use to create a number as a string with leading zeros
int_string_new = formatter % (int_new,) # applies that format
new_filename = prefix+"_"+int_string_new # put it all together
if extension: # add the extension if present in original name
new_filename += "."+extension
return new_filename
# since we only want to do this when the file already exists, check if it exists and execute function if so
our_filename = 'file_0026.txt'
while os.path.isfile(our_filename):
our_filename = get_next_filename(our_filename) # loop until a unique filename found
I am writing some hints to acheive that. It's unclear what exactly you wanna achieve?
fh = open("fileName_0026.txt","r") #Read a file
t= fh.read() #Read the content
name= t.split("_|.") #Output:: [fileName,0026,txt]
n=str(int(name[1])+1) #27
s= n.zfill(2) #0027
newName= "_".join([fileName,s])+".txt" #"fileName_0027.txt"
fh = open(newName,"w") #Write a new file*emphasized text*
Use the rjust function from string
O=fileName_0026
P=Retrieved padding from original file (4)
CN=retrieve current file number (26)
NN=add 1 to current file number (27)
new_padding = str(NN).rjust(P, '0')
Result=fileName_ + new_padding
import re
m = re.search(r".*_(0*)(\d*)", "filenName_00023")
print m.groups()
print("fileName_{0:04d}".format(int(m.groups()[1])+1))
{0:04d} means pad out to four digits wide with leading zeros.
As you can see there are a few ways to do this that are quite similar. But one thing the other answers haven't mention is that it's important to strip off any existing leading zeroes from your file's number string before converting it to int, otherwise it will be interpreted as octal.
edit
I just realised that my previous code crashes if the file number is zero! :embarrassed:
Here's a better version that also copes with a missing file number and names with multiple or no underscores.
#! /usr/bin/env python
def increment_filename(s):
parts = s.split('_')
#Handle names without a number after the final underscore
if not parts[-1].isdigit():
parts.append('0')
tail = parts[-1]
try:
n = int(tail.lstrip('0'))
except ValueError:
#Tail was all zeroes
n = 0
parts[-1] = str(n + 1).zfill(len(tail))
return '_'.join(parts)
def main():
for s in (
'fileName_0026',
'data_042',
'myfile_7',
'tricky_99',
'myfile_0',
'bad_file',
'worse_file_',
'_lead_ing_under_score',
'nounderscore',
):
print "'%s' -> '%s'" % (s, increment_filename(s))
if __name__ == "__main__":
main()
output
'fileName_0026' -> 'fileName_0027'
'data_042' -> 'data_043'
'myfile_7' -> 'myfile_8'
'tricky_99' -> 'tricky_100'
'myfile_0' -> 'myfile_1'
'bad_file' -> 'bad_file_1'
'worse_file_' -> 'worse_file__1'
'_lead_ing_under_score' -> '_lead_ing_under_score_1'
'nounderscore' -> 'nounderscore_1'
Some additional refinements possible:
An optional arg to specify the number to add to the current file
number,
An optional arg to specify the minimum width of the file
number string,
Improved handling of names with weird number / position of
underscores.

Categories