Python code to produce C++14 hex integer literal with ticks

0

tl;dr? See bottom for The Competition

Integer literals

While programming, the 64-bit hexadecimal literal 0x123456789abcdefL is difficult to gauge the size of. I find myself mentally grouping digits from the right by fours to see that it's 15 digits' worth.

Python PEP 515 allows you to express the above literal, inside code, as 0x123_4567_89ab_cdefL. If you prefer binary, then it's even more invaluable: 0b1_0010_0011_0100_0101_0110_0111_1000_1001_1010_1011_1100_1101_1110_1111L

String representations

Python can also convert an integer into strings with spacing characters, as follows:

'{:#_b}'.format(81985529216486895L)
'{:#_x}'.format(81985529216486895L)
'{:,}'.format(81985529216486895L)

The first two produce what's shown above (although without the L suffix), while the last will produce

"81,985,529,216,486,895"

Although with PEP 515, they would be better expressed as:

'{:#_b}'.format(81_985_529_216_486_895L)
'{:#_x}'.format(81_985_529_216_486_895L)
'{:,}'.format(81_985_529_216_486_895L)

Note, though, the following:

  • '_' is only legal for binary and hexadecimal strings - and Python will insert them every four characters (from the right);
  • ',' is only legal for decimal strings - and Python will insert them every three characters (from the right);
  • No other separator characters are allowed.

Enough with the Python syntax lesson; on to C++!

C++14 also allows separators inside an integer literal to allow grouping, much like the above. Only (of course) it's a different character: the tick (single quote '). So the above literals would be:

0b1'0010'0011'0100'0101'0110'0111'1000'1001'1010'1011'1100'1101'1110'1111uL
0x123'4567'89ab'cdefuL
81'985'529'216'486'895uL

Python is often used to machine-generate C/C++ code, because it's so easy to do! But there's no native Python way to generate these new 'tick'-based identifiers - .format() can only use _. So, here's some code that I wrote to do it:

# Hex function with tick marks
def HexTicks(num) :
  # Convert to hex (without leading 0x - yet)
  s = '{:x}'.format(num)
  # Insert tick marks
  for i in range(len(s)-4, 0, -4) :
    s = s[:i] + "'" + s[i:]
  # Return the result
  return "0x" + s + "uLL"

The Competition

Sorry @ASCII-only !

Write a Python 2.7.3 expression or lambda, smaller than the above function (not including whitespace or comments), that:

  1. Takes any non-negative integer;
  2. Produces the correct hexadecimal string for that integer;
  3. With a leading 0x and trailing uLL;
  4. No leading zeroes as part of the hex number;
  5. With tick marks (') every four digits, counting backwards from the right;
  6. No tick mark straight after the 0x.

ILLEGAL

0x0uLL       # If integer was anything other than zero (2.)
12'3456      # No 0x or uLL (3.)
0x0'1234uLL  # Leading zero (4.)
0x12'345uLL  # Not grouped by four (5.)
0x'1234uLL   # Tick mark before hex number (6.)

Bonuses

A. Can be easily modified to produce capital hex letters - but not the 0x or uLL parts;

Note that .format() allows '{:_X}' to capitalise the hex characters - but '{:#_X}' will capitalise the 0X too

B. An extra digits parameter that will add leading zeros to that number of digits (not resultant characters; just hex digits) - unless it's already got that many.

For example: HexTick(0x1234,6) would produce "0x00'1234uLL"

John Burger

Posted 2019-02-20T04:48:31.063

Reputation: 117

5I'd advise against restricting the language here, and imposing a maximum size limit for that matter. Also, bonuses are very, very frowned because there is no objective best way to score them - in fact, in your case they provide no bonus and therefore will never be done in a seriously competing answer. – ASCII-only – 2019-02-20T04:56:24.257

1Also, if you do stick with this, please specify Python version... – ASCII-only – 2019-02-20T04:57:53.153

What are the bonuses worth? Please give them a value. – Rɪᴋᴇʀ – 2019-02-20T04:59:52.890

5

Hi and welcome to PPCG! You seem to have put a lot of effort into understanding the quality and precision we demand from challenge writers, and for that I'd like to say thank you. However, this challenge is rather out of "culture" for this site. There are quite a few points of contention that I think the community will have, so I'd like to direct you to the sandbox where you could receive feedback before posting to the main site. Good luck :)

– FryAmTheEggman – 2019-02-20T05:01:50.580

239 bytes :P – ASCII-only – 2019-02-20T05:03:51.863

both bonuses, 55 – ASCII-only – 2019-02-20T05:15:20.423

@ASCII-only I really liked the (d*5-1)//4 - that's using your math! But D'oh! I fully intended on specifying Python version - and it slipped my mind while I was dreaming up potential loopholes. (Simply "0x0uLL" would have passed two minutes before I hit "Submit"!) – John Burger – 2019-02-20T05:33:56.840

Oops, deleted my comment when you were writing a reply :/ – ASCII-only – 2019-02-20T05:37:05.283

wip, 73 – ASCII-only – 2019-02-20T05:46:35.450

2@ASCII-only Why not post as answers? – tsh – 2019-02-20T07:57:47.703

@tsh The first two are in the wrong language, the third is WIP :P – ASCII-only – 2019-02-20T13:07:14.200

1Why is it limited to Python? Can you change the requirement so that we can provide answers in other languages? – Olivier Grégoire – 2019-02-20T13:27:30.773

Answers

2

Python 2, 68 65 bytes

-3 bytes for both thanks to tsh

lambda n:"0x"+re.sub("(?!^)(?=(....)+u)","'","%xuLL"%n)
import re

Try it online!

Eligible for both bonuses, 76 73 bytes

lambda x,d:"0x"+re.sub("(?!^)(?=(....)+u)","'","%%0%dxuLL"%d%x)
import re

Try it online!

ASCII-only

Posted 2019-02-20T04:48:31.063

Reputation: 4 687

1Use import re and re.sub would save bytes. – tsh – 2019-02-21T02:47:30.333

1Alternative for the same cost: lambda n:re.sub("(?<!x)(?=([^x]{4})+u)","'","%#xuLL"%n) – Peter Taylor – 2019-02-21T11:28:08.250