I have a string like x = "http://query.yahooapis.com/v1/public/yql?q=select%20owner%2Curls%20from%20flickr.photos.info%20where%20photo_id%3D'%s'&format=json"
If I do x % 10 that fails as there are %20f etc which are being treated as format strings, so I have to do a string conactination. How can I use normal string replacements here.?
urldecode the string, do the formatting, and then urlencode it again:
import urllib
x = "http://query.yahooapis.com/v1/public/yql?q=select%20owner%2Curls%20from%20flickr.photos.info%20where%20photo_id%3D'%s'&format=json"
tmp = urllib.unquote(x)
tmp2 = tmp % (foo, bar)
x = urllib.quote(tmp2)
As one commenter noted, doing formatting using arbitrary user-inputted strings as the format specification is historically dangerous, and is certainly a bad idea.
In python string formatting, use %% to output a single % character (docs).
>>> "%d%%" % 50
'50%'
So you could replace all the % with %%, except where you want to substitute during formatting. But #Conrad Meyer's solution is obviously better in this case.
Otherwise you can use the new-style output formatting (available since v 2.6), which doesn't rely on %:
x = 'http://query.yahooapis.com/v1/public/yql?q=select%20owner%2Curls%20from%20flickr.photos.info%20where%20photo_id%3D{0}&format=json'
x.format(10)
It also has the advance of not being typedependent.
Related
In a project of mine, I'm passing strings to a Formatter subclass whic formats it using the format specifier mini-language. In my case it is customized (using the features of the Formatter class) by adding additional bang converters : !u converts the resulting string to lowercase, !c to titlecase, !q doubles any square bracket (because reasons), and some others.
For example, using a = "toFu", "{a!c}" becomes "Tofu"
How could I make my system use f-string syntax, so I can have "{a+a!c}" be turned into "Tofutofu" ?
NB: I'm not asking for a way of making f"{a+a!c}" (note the presence of an f) resolve itself as "Tofutofu", which is what hook into the builtin python f-string format machinery covers, I'm asking if there is a way for a function or any form of python code to turn "{a+a!c}" (note the absence of an f) into "Tofutofu".
Not sure I still fully understand what you need, but from the details given in the question and some comments, here is a function that parses strings with the format you specified and gives the desired results:
import re
def formatter(s):
def replacement(match):
expr, frmt = match[1].split('!')
if frmt == 'c':
return eval(expr).title()
return re.sub(r"{([^{]+)}", replacement, s)
a = "toFu"
print(formatter("blah {a!c}"))
print(formatter("{a+a!c}blah"))
Outputs:
blah Tofu
Tofutofublah
This uses the function variation of the repl argument of the re.sub function. This function (replacement) can be further extended to support all other !xs.
Main disadvantages:
Using eval is evil.
This doesn't take in count regular format specifiers, i.e. :0.3
Maybe someone can take it from here and improve.
Evolved from #Tomerikoo 's life-saving answer, here's the code:
import re
def formatter(s):
def replacement(match):
pre, bangs, suf = match.group(1, 2, 3)
# pre : the part before the first bang
# bangs : the bang (if any) and the characters going with it
# suf : the colon (if any) and the characters going with it
if not bangs:
return eval("f\"{" + pre + suf + "}\"")
conversion = set(bangs[1:]) # the first character is always a bang
sra = conversion - set("tiqulc")
conversion = conversion - sra
if sra:
sra = "!" + "".join(sra)
value = eval("f\"{" + pre + (sra or "") + suf + "}\"")
if "q" in conversion:
value = value.replace("{", "{{")
if "u" in conversion:
value = value.upper()
if "l" in conversion:
value = value.lower()
if "c" in conversion and value:
value = value.capitalize()
return value
return re.sub(r"{([^!:\n]+)((?:![^!:\n]+)?)((?::[^!:\n]+)?)}", replacement, s)
The massive regex results in the three groups I commented about at the top.
Caveat: it still uses eval (no acceptable way around it anyway), it doesn't allow for multiline replacement fields, and it may cause issues and/or discrepancies to put spaces between the ! and the :.
But these are acceptable for the use I have.
Please check specifcation
only those characters are allowed : 's', 'r', or 'a'
https://peps.python.org/pep-0498/
I want to kind of implement my own struct.pack specific function to pack an IP string (i.e. "192.168.0.1") to a 32-bit packed value, without using the socket.inet_aton built in method.
I got so far:
ip = "192.168.0.1"
hex_list = map(hex, map(int, ip.split('.')))
# hex list now is : ['0xc0', '0xa8', '0x0', '0x01']
My question is:
How do I get from that ['0xc0', '0xa8', '0x0', '0x01'] to '\xc0\xa8\x00\x01', (this is what I'm getting from socket.inet_aton(ip)?
(And also - How is it possible that there is a NUL (\x00) in the middle of that string? I think I lack some understanding of the \x format)
You can use string comprehension to format as you like:
ip = "192.168.0.1"
hex_list = map(int, ip.split('.'))
hex_string = ''.join(['\\x%02x' % x for x in hex_list])
or as a one liner:
hex_string = ''.join(['\\x%02x' % int(x) for x in ip.split('.')])
An alternative:
Can you use ipaddress and to_bytes (python 3.2)?
>>> import ipaddress
>>> address = ipaddress.IPv4Address('192.168.0.1')
>>> address_as_int = int(address)
>>> address_as_int.to_bytes(4, byteorder='big')
b'\xc0\xa8\x00\x01'
Note that you may actually only need the integer.
Can be shorter obviously, but wanted to show all steps clearly :)
Based loosely off #Stephen's answer but returns a string with the actual bytes rather than a string with literal slashes:
def pack_ip(ip):
num_list = map(int, ip.split('.'))
return bytearray(num_list)
src_ip = pack_ip('127.0.0.255')
print(repr(src_ip))
Works in Python 2 and 3. Returns a b'' rather than a string, matching best practice for Python3.
The hex() function in python, puts the leading characters 0x in front of the number. Is there anyway to tell it NOT to put them? So 0xfa230 will be fa230.
The code is
import fileinput
f = open('hexa', 'w')
for line in fileinput.input(['pattern0.txt']):
f.write(hex(int(line)))
f.write('\n')
(Recommended)
Python 3 f-strings: Answered by #GringoSuave
>>> i = 3735928559
>>> f'{i:x}'
'deadbeef'
Alternatives:
format builtin function (good for single values only)
>>> format(3735928559, 'x')
'deadbeef'
And sometimes we still may need to use str.format formatting in certain situations #Eumiro
(Though I would still recommend f-strings in most situations)
>>> '{:x}'.format(3735928559)
'deadbeef'
(Legacy) f-strings should solve all of your needs, but printf-style formatting is what we used to do #msvalkon
>>> '%x' % 3735928559
'deadbeef'
Without string formatting #jsbueno
>>> i = 3735928559
>>> i.to_bytes(4, "big").hex()
'deadbeef'
Hacky Answers (avoid)
hex(i)[2:] #GuillaumeLemaître
>>> i = 3735928559
>>> hex(i)[2:]
'deadbeef'
This relies on string slicing instead of using a function / method made specifically for formatting as hex. This is why it may give unexpected output for negative numbers:
>>> i = -3735928559
>>> hex(i)[2:]
'xdeadbeef'
>>> f'{i:x}'
'-deadbeef'
Use this code:
'{:x}'.format(int(line))
it allows you to specify a number of digits too:
'{:06x}'.format(123)
# '00007b'
For Python 2.6 use
'{0:x}'.format(int(line))
or
'{0:06x}'.format(int(line))
You can simply write
hex(x)[2:]
to get the first two characters removed.
Python 3.6+:
>>> i = 240
>>> f'{i:x}' # 02x to pad with zeros
'f0'
Old style string formatting:
In [3]: "%x" % 127
Out[3]: '7f'
New style
In [7]: '{:x}'.format(127)
Out[7]: '7f'
Using capital letters as format characters yields uppercase hexadecimal
In [8]: '{:X}'.format(127)
Out[8]: '7F'
Docs are here.
'x' - Outputs the number in base 16, using lower-case letters for the digits above 9.
>>> format(3735928559, 'x')
'deadbeef'
'X' - Outputs the number in base 16, using upper-case letters for the digits above 9.
>>> format(3735928559, 'X')
'DEADBEEF'
You can find more information about that in Python's documentation:
Format Specification Mini-Language
format()
F-strings
Python 3's formatted literal strings (f-strings) support the Format Specification Mini-Language, which designates x for hexadecimal numbers. The output doesn't include 0x.
So you can do this:
>>> f"{3735928559:x}"
'deadbeef'
See the spec for other bases like binary, octal, etc.
Edit: str.removeprefix
Since Python 3.9, there is now a str.removeprefix method, which allows you to write the following more obvious code:
>>> hexadecimal = hex(3735928559)
>>> hexadecimal.removeprefix('0x')
'deadbeef'
Not that this does NOT work for negative numbers ❌:
>>> negadecimal = hex(-3735928559)
>>> negadecimal.removeprefix('0x')
'-0xdeadbeef'
Besides going through string formatting, it is interesting to have in mind that when working with numbers and their hexadecimal representation we usually are dealing with byte-content, and interested in how bytes relate.
The bytes class in Python 3 had been enriched with methods over the 3.x series, and int.to_bytes combined with the bytes.hex() provide full control of the hex-digits output, while preserving the semantics of the transform (not to mention, holding the intermediate "bytes" object ready to be used in any binary protocol that requires the number):
In [8]: i = 3735928559
In [9]: i.to_bytes(4, "big").hex()
Out[9]: 'deadbeef'
Besides that, bytes.hex() allow some control over the output, such as specifying a separator for the hex digits:
In [10]: bytes.hex?
Docstring:
Create a string of hexadecimal numbers from a bytes object.
sep
An optional single character or byte to separate hex bytes.
bytes_per_sep
How many bytes between separators. Positive values count from the
right, negative values count from the left.
Example:
>>> value = b'\xb9\x01\xef'
>>> value.hex()
'b901ef'
>>> value.hex(':')
'b9:01:ef'
>>> value.hex(':', 2)
'b9:01ef'
>>> value.hex(':', -2)
'b901:ef'
(That said, in most scenarios just a quick print is wanted, I'd probably just go through f-string formatting, as in the accepted answer: f"{mynumber:04x}" - for the simple reason of "less things to remember")
While all of the previous answers will work, a lot of them have caveats like not being able to handle both positive and negative numbers or only work in Python 2 or 3. The version below works in both Python 2 and 3 and for positive and negative numbers:
Since Python returns a string hexadecimal value from hex() we can use string.replace to remove the 0x characters regardless of their position in the string (which is important since this differs for positive and negative numbers).
hexValue = hexValue.replace('0x','')
EDIT: wjandrea made a good point in that the above implementation doesn't handle values that contain 0X instead of 0x, which can occur in int literals. With this use case in mind, you can use the following case-insensitive implementation for Python 2 and 3:
import re
hexValue = re.sub('0x', '', hexValue, flags=re.IGNORECASE)
Decimal to Hexadecimal,
it worked
hex(number).lstrip("0x").rstrip("L")
Does anyone know how to get a chr to hex conversion where the output is always two digits?
for example, if my conversion yields 0x1, I need to convert that to 0x01, since I am concatenating a long hex string.
The code that I am using is:
hexStr += hex(ord(byteStr[i]))[2:]
You can use string formatting for this purpose:
>>> "0x{:02x}".format(13)
'0x0d'
>>> "0x{:02x}".format(131)
'0x83'
Edit: Your code suggests that you are trying to convert a string to a hexstring representation. There is a much easier way to do this (Python2.x):
>>> "abcd".encode("hex")
'61626364'
An alternative (that also works in Python 3.x) is the function binascii.hexlify().
You can use the format function:
>>> format(10, '02x')
'0a'
You won't need to remove the 0x part with that (like you did with the [2:])
If you're using python 3.6 or higher you can also use fstrings:
v = 10
s = f"0x{v:02x}"
print(s)
output:
0x0a
The syntax for the braces part is identical to string.format(), except you use the variable's name. See https://www.python.org/dev/peps/pep-0498/ for more.
htmlColor = "#%02X%02X%02X" % (red, green, blue)
The standard module binascii may also be the answer, namely when you need to convert a longer string:
>>> import binascii
>>> binascii.hexlify('abc\n')
'6162630a'
Use format instead of using the hex function:
>>> mychar = ord('a')
>>> hexstring = '%.2X' % mychar
You can also change the number "2" to the number of digits you want, and the "X" to "x" to choose between upper and lowercase representation of the hex alphanumeric digits.
By many, this is considered the old %-style formatting in Python, but I like it because the format string syntax is the same used by other languages, like C and Java.
The simpliest way (I think) is:
your_str = '0x%02X' % 10
print(your_str)
will print:
0x0A
The number after the % will be converted to hex inside the string, I think it's clear this way and from people that came from a C background (like me) feels more like home
I'm trying to do this:
max_title_width = max([len(text) for text in columns])
for column in columns:
print "%10s, blah" % column
But I want to replace the 10 with the value of max_title_width. How do I do this in the most pythonic way possible?
This is a carryover from the C formatting markup:
print "%*s, blah" % (max_title_width,column)
If you want left-justified text (for entries shorter than max_title_width), put a '-' before the '*'.
>>> text = "abcdef"
>>> print "<%*s>" % (len(text)+2,text)
< abcdef>
>>> print "<%-*s>" % (len(text)+2,text)
<abcdef >
>>>
If the len field is shorter than the text string, the string just overflows:
>>> print "<%*s>" % (len(text)-2,text)
<abcdef>
If you want to clip at a maximum length, use the '.' precision field of the format placeholder:
>>> print "<%.*s>" % (len(text)-2,text)
<abcd>
Put them all together this way:
%
- if left justified
* or integer - min width (if '*', insert variable length in data tuple)
.* or .integer - max width (if '*', insert variable length in data tuple)
You have the new strings formatting methods from Python 3 and Python 2.6.
Starting in Python 2.6, the built-in str and unicode classes provide the ability to do complex variable substitutions and value formatting via the str.format() method described in PEP 3101. The Formatter class in the string module allows you to create and customize your own string formatting behaviors using the same implementation as the built-in format() method.
(...)
For example, suppose you wanted to have a replacement field whose field width is determined by another variable:
>>> "A man with two {0:{1}}.".format("noses", 10)
"A man with two noses ."
>>> print("A man with two {0:{1}}.".format("noses", 10))
A man with two noses .
So for your example it would be
max_title_width = max(len(text) for text in columns)
for column in columns:
print "A man with two {0:{1}}".format(column, max_title_width)
I personally love the new formatting methods, as they are far more powerful and readable in my humble opinion.
Python 2.6+ alternate version examples:
>>> '{:{n}s}, blah'.format('column', n=10)
'column , blah'
>>> '{:*>{l}s}'.format(password[-3:], l=len(password)) # password = 'stackoverflow'
'**********low'
>>> '{:,.{n}f} {}'.format(1234.567, 'USD', n=2)
'1,234.57 USD'
Hint: first non-keyword args, then keyword args.
you could create your template outside of the loop:
tmpl = '%%%ds, blah' % max_title_width
for column in columns:
print tmpl % column
You could also learn about the new formatting in python.
and btw, max doesn't require a list, you can pass it an iterable:
max_title_width = max(len(i) for i in columns)