Objective

Given an ASCII string, decide whether it is a valid C integer literal.

C integer literal

A C integer literal consists of:

• One of:

• 0 followed by zero or more octal digits (07)

• A nonzero decimal digit followed by zero or more decimal digits (09)

• 0X or 0x, followed by one or more hexadecimal digits (09, AF, and af)

• optionally followed by one of:

• One of U or u, which are the "unsigned" suffixes

• One of L, l, LL, or ll, which are the "long" and "long long" suffixes

• Any combination of the above, in any order.

Note that there can be arbitrarily many digits, even though C doesn't support arbitrary-length integers. Likewise, even if the literal with l and co would overflow the long type or co, it is still considered a valid literal.

Also note that there must not be a leading plus or minus sign, for it is not considered to be a part of the literal.

Rules

• It is implementation-defined to accept leading or trailing whitespaces.

• Non-ASCII string falls in don't care situation.

Examples

Truthy

• 0

• 007

• 42u

• 42lu

• 42UL

• 19827489765981697847893769837689346573uLL (Digits can be arbitrarily many even if it wouldn't fit the unsigned long long type)

• 0x8f6aa032838467beee3939428l (So can to the long type)

• 0XCa0 (You can mix cases)

Falsy

• 08 (Non-octal digit)

• 0x (A digit must follow X or x)

• -42 (Leading signature isn't a part of the literal)

• 42Ll (Only LL or ll is valid for the long long type)

• 42LLLL (Redundant type specifier)

• 42Uu (Redundant type specifier)

• 42Ulu (Redundant type specifier)

• 42lul (Redundant type specifier)

• 42H (Invalid type specifier)

• 0b1110010000100100001 (Valid C++, but not valid C)

• Hello

• Empty string

Ungolfed solution

Doesn't recognize leading or trailing whitespaces.

Returns () on success. Monadic failure otherwise.

decideCIntegerLit = do
choice [
do
'0' <- get
munch (flip elem "01234567"),
do
satisfy (flip elem "123456789")
munch (flip elem "0123456789"),
do
'0' <- get
satisfy (flip elem "Xx")
munch1 (flip elem "0123456789ABCDEFabcdef")
]
let unsigned = satisfy (flip elem "Uu")
let long = string "l" +++ string "L" +++ string "ll" +++ string "LL"
(unsigned >> long >> return ()) +++ (optional long >> optional unsigned)
eof
• Suggested falsey test cases: 1L1L, 0xabucdlu (or any other test case with an l/L/u somewhere in the middle, making it invalid). Oct 14 '20 at 8:33
• Suggested test case for floating point values Oct 14 '20 at 8:46
• Suggested test-case: 2-1 (starts with a digit and is a valid C constant-expression, but not a bare integer literal). So for example feeding a=2-1; or a[2-1]; to a C compiler wouldn't reject it. (Working on a bash answer that uses cc -c after testing the first digit, trying to let a compiler do the heavy lifting.) Oct 14 '20 at 12:56
• Suggested test case: 0o765. This is a valid octal literal in many languages that might try to get away with a built-in "eval" / "read-int" sort of approach, but it's not valid C.
– Lynn
Oct 14 '20 at 16:21
• "Any combination of the above", as written, seems to include many of the possibilities you list as invalid examples (Ll for example). Can you clarify what combinations are allowed? Oct 14 '20 at 16:22

Retina 0.8.2, 60 59 bytes

i^(0[0-7]*|0x[\da-f]+|[1-9]\d*)(u)?(l)?(?-i:\3?)(?(2)|u?)$Try it online! Link includes test cases. Edit: Saved 1 byte thanks to @FryAmTheEggMan. Explanation: i Match case-insensitively. ^(0[0-7]*|0x[\da-f]+|[1-9]\d*) Start with either octal, hex or decimal. (u)? Optional unsigned specifier. (l)? Optional length specifier. (?-i:\3?) Optionally repeat the length specifier case sensitively. (?(2)|u?)$

If no unsigned specifier yet, then another chance for an optional specifier, before the end of the literal.

• You can use \d in the hex character class, too. Oct 14 '20 at 0:22

Perl 5-p, 65 61 bytes

@NahuelFouilleul shaved 4 bytes

$_=/^(0[0-7]*|0x\p{Hex}+|[1-9]\d*)(u?l?l?|l?l?u?)$/i*!/lL|Ll/

Try it online!

• could save 2 bytes using l?l? instead of l{0,2} Oct 14 '20 at 9:24
• 61 bytes Oct 14 '20 at 9:50

Java 8 / Scala polyglot, 89 79 bytes

s->s.matches("(?!.*(Ll|lL))(?i)(0[0-7]*|[1-9]\\d*|0x[\\da-f]+)(u?l?l?|l?l?u?)")

-10 bytes thanks to @NahuelFouilleul

Try it online in Java 8.
Try it online in Scala (except with => instead of -> - thanks to @TomerShetah).

Explanation:

s->           // Method with String parameter and boolean return-type
s.matches(  //  Check whether the input-string matches the regex
"(?!.*(Ll|lL))(?i)(0[0-7]*|[1-9]\\d*|0x[\\da-f]+)(u?l?l?|l?l?u?)")

Regex explanation:

In Java, the String#matches method implicitly adds a leading and trailing ^...$to match the entire string, so the regex is: ^(?!.*(Ll|lL))(?i)(0[0-7]*|[1-9]\d*|0x[\da-f]+)(u?l?l?|l?l?u?)$
(?!         )     # The string should NOT match:
^   .*             #   Any amount of leading characters
(     )      #   Followed by:
Ll          #    "Ll"
|lL       #    Or "lL"
# (Since the ?! is a negative lookahead, it acts loose from the
#  rest of the regex below)

(?i)              # Using case-insensitivity,
0           #   A 0
[0-7]*     #   Followed by zero or more digits in the range [0,7]
|            #  OR:
[1-9]       #   A digit in the range [1,9]
\d*    #   Followed by zero or more digits
|            #  OR:
0x          #   A "0x"
[     ]+  #   Followed by one or more of:
\d       #    Digits
a-f    #    Or letters in the range ['a','f']
)(            # And with nothing in between,

Original:

using c=System.Console;using System.Text.RegularExpressions;class P{static void Main(){c.WriteLine(Regex.IsMatch(c.ReadLine(),@"^(?!.*(Ll|lL))(?i)(0[0-7]*|[1-9]\d*|0x[\da-f]+)(u?l?l?|l?l?u?)$"));}} Try it online! • Nice first answer, welcome to the site! Oct 14 '20 at 13:45 • Since Regex is used only once, you can write System.Text.RegularExpressions.Regex and remove the using statement, saving 6 bytes. Oct 16 '20 at 13:38 • @nwellnhof Thanks for noticing! Oct 16 '20 at 23:24 Python 3, 103 bytes import re;re.compile("^(0[0-7]*|[1-9]\d*|0[xX][\dA-Fa-f]+)([uU](L|l|LL|ll)?|(L|l|LL|ll)[uU]?)?$").match

Try it online!

just a basic regex, probably very suboptimal

returns a match object for truthy and None for falsy; input may not contain surrounding whitespace

-3 bytes thanks to Digital Trauma (on my Retina answer)
-1 byte thanks to FryAmTheEggman (on my Retina answer)
-3 bytes thanks to pxeger

• This is why regexes are so fun. Oct 14 '20 at 0:02
• 103 bytes Oct 14 '20 at 19:25
• @pxeger Oh cool, thanks! Oct 14 '20 at 19:55

^(0[0-7]*|[1-9]\d*|0[xX][\dA-Fa-f]+)([uU](L|l|LL|ll)?|(L|l|LL|ll)[uU]?)?$Try it online! Just the same regex I used. First time using Retina, I'm sure this can be optimized with some Retina golf things! -3 bytes thanks to Digital Trauma -1 byte thanks to FryAmTheEggman • Also never used Retina, but 55 bytes? Oct 14 '20 at 0:07 • @cairdcoinheringaahing I thought of that; unfortunately, no. but thanks for trying :P Oct 14 '20 at 0:07 Charcoal, 76 bytes ≔⊟Φ³¬⌕↧θ…0xιη≔✂↧θη⁻ＬθＬ⊟Φ⪪”{“↧←；⭆δa”¶⁼ι↧…⮌θＬι¹ζ›∧⁺Ｌζ¬⊖η⬤ζ№Ｅ∨×⁸ηχ⍘λφι∨№θLl№θlL Try it online! Link is to verbose version of code. Explanation: ≔⊟Φ³¬⌕↧θ…0xιη Find the length of the longest prefix of 0x in the lowercased input. ≔✂↧θη⁻ＬθＬ⊟Φ⪪”{“↧←；⭆δa”¶⁼ι↧…⮌θＬι¹ζ Slice off the prefix and also check for a lowercase suffix of ull, ul, llu or lu, and if so then slice that off as well. ›...∨№θLl№θlL The original input must not contain Ll or lL. ∧⁺Ｌζ¬⊖η The sliced string must not be empty unless the prefix was 0. ⬤ζ№Ｅ∨×⁸ηχ⍘λφι Convert the prefix length to 10, 8 or 16 appropriately, then take that many base 62 digits and check that all of the remaining lowercased characters are one of those digits. 05AB1E, 6361 62 bytes „Uuõª„LLæDl«âDí«JéRʒÅ¿}нõ.;Ðć_ilDć'xQiA6£мÐþQë\7ÝKõQë\þQ}sõÊ* This isn't too easy without regexes.. :/ Can definitely be golfed a bit more, though. +1 byte as bug-fix for inputs like "u", "l", "LL", etc. (thanks for noticing @Neil) Explanation: „Uu # Push string "Uu" õª # Convert it to a list of characters, and append an empty string: # ["U","u",""] „LL # Push string "LL" æ # Take its powerset: ["","L","L","LL"] Dl # Create a lowercase copy: ["","l","l","ll"] « # Merge the lists together: ["","L","L","LL","","l","l","ll"] â # Create all possible pairs of these two lists Dí # Create a copy with each pair reversed « # Merge the list of pairs together J # Join each pair together to a single string éR # Sort it by length in descending order We now have the list: ["llu","LLu","llU","LLU","ull","uLL","Ull","ULL","ll","LL","lu","lu","Lu","Lu","lU","lU","LU","LU","ll","LL","ul","ul","uL","uL","Ul","Ul","UL","UL","l","l","L","L","u","u","U","U","l","l","L","L","u","u","U","U","","","",""] ʒ # Filter this list by: Å¿ # Where the (implicit) input ends with this string }н # After the filter: only leave the first (longest) one õ.; # And remove the first occurrence of this in the (implicit) input ÐD # Triplicate + duplicate (so there are 4 copies on the stack now) ć # Extract head; pop and push remainder-string and first character # separated to the stack _i # If this first character is a 0: l # Convert the remainder-string to lowercase D # Duplicate it †¹ ć # Extract head again 'xQi '# If it's equal to "x": A # Push the lowercase alphabet 6£ # Only leave the first 6 characters: "abcdef" м # Remove all those characters from the string Ð # Triplicate it †² þ # Only keep all digits in the copy Q # And check that the two are still the same # (thus it's a non-negative integer without decimal .0s) ë # Else: \ # Discard the remainder-string 7Ý # Push list [0,1,2,3,4,5,6,7] K # Remove all those digits õQ # Check what remains is an empty string ë # Else: \ # Discard the remainder-string þ # Only keep all digits Q # And check that the two are still the same # (thus it's a non-negative integer without decimal .0s) }s # After the if-else: Swap the two values on the stack # (this will get the remaining copy of †² for "0x" cases, # or the remaining copy of †¹ for other cases) õÊ # Check that this is NOT an empty string * # And check that both are truthy # (after which the result is output implicitly) • This incorrectly outputs 1 for u... – Neil Oct 14 '20 at 14:15 • @Neil Thanks for noticing. Fixed at the cost of 1 byte. Oct 14 '20 at 14:21 AWK, 86 bytes {print/^(0[0-7]*|[1-9][0-9]*|0[xX][0-9A-Fa-f]+)([uU](L|l|LL|ll)?|(L|l|LL|ll)[uU]?)?$/}

Try it online!

Simply prints truthy or falsey depending on whether or not the input line matches the regex. Doesn't accept leading or trailing whitespaces.

JavaScript (ES6),  77  76 bytes

Saved 1 byte thanks to @l4m2

s=>/^(0x[\da-f]+|0[0-7]*|[1-9]\d*)(u?l?l?|l?l?u?)$/i.test(s)>/Ll|lL/.test(s) Try it online! How? The first regex is case-insensitive. The only invalid patterns that cannot be filtered out that way are "Ll" and "lL". So we use a 2nd case-sensitive regex to take care of them. • &! => >.... – l4m2 Mar 19 at 13:30 Haskell, 169 bytes import Data.Char s!p=s>""&&dropWhile p selemdo u<-["","u","U"];l<-"":words"L l LL ll";[u++l,l++u] f('0':x:s)|elem x"xX"=s!isHexDigit|1<2=(x:s)!isOctDigit f s=s!isDigit Try it online! Ruby, 67 bytes ->s{/^(0[0-7]*|[1-9]\d*|0x[\da-f]+)(u?l?l?|l?l?u?)?$/i=~s&&/Ll/!~s}

Try it online!

• Fails for 0lL, no?
– Neil
Oct 21 '20 at 13:58
• @Neil uhh no? 0lL is invalid (right?), and this returns false for that. Oct 21 '20 at 18:14
• When I Try it online! it outputs true...
– Neil
Oct 21 '20 at 20:26

Elixir, 74 bytes

&(&1=~~r/^(0[0-7]*|[1-9]\d*|0x[\da-f]+)(u?l?l?|l?l?u?)?\$/i&&!(&1=~~r/Ll/))

Try it online!