Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In mathematics, an exclamation mark ! often means factorial, and it comes after the argument.

In programming, an exclamation mark ! often means negation, and it comes before the argument.

For this challenge we'll only apply these operations to zero and one.

Factorial
0! = 1
1! = 1

Negation
!0 = 1
!1 = 0

Take a string of zero or more !'s, followed by 0 or 1, followed by zero or more !'s (/!*[01]!*/).
For example, the input may be !!!0!!!! or !!!1 or !0!! or 0! or 1.

The !'s before the 0 or 1 are negations and the !'s after are factorials.

Factorial has higher precedence than negation so factorials are always applied first.
For example, !!!0!!!! truly means !!!(0!!!!), or better yet !(!(!((((0!)!)!)!))).

Output the resultant application of all the factorials and negations. The output will always be 0 or 1.

Test Cases

0 -> 0
1 -> 1
0! -> 1
1! -> 1
!0 -> 1
!1 -> 0
!0! -> 0
!1! -> 0
0!! -> 1
1!! -> 1
!!0 -> 0
!!1 -> 1
!0!! -> 0
!!!1 -> 0
!!!0!!!! -> 0
!!!1!!!! -> 0

The shortest code in bytes wins.

share|improve this question
13  
But 0!=1!, so what's the point of handling multiple factorials? – boboquack 2 days ago
13  
@boboquack Because that's the challenge. – Helka Homba 2 days ago
46  
+1 just for the title! – ojdo yesterday
4  
<?='1'; ... correct 75% of the time in php. – aslum yesterday
5  
I may be wrong here but can't any number with any factorials after it simply be removed and replaced with 1? Like 0!!!! = 1!! = 0!!!!!!!! = 1!!! = 1! = 0! = 1 etc – Albert Renshaw yesterday

31 Answers 31

Mathematica, 25 17 bytes

Input[]/.!x_:>1-x

Takes input from a user prompt. Assumes Mathematica's notebook environment for implicit printing. To make it a command-line script, wrap it in Print[...] or to make it an argumentless function (which then takes input from the prompt), append &.

Mathematica has both of the required operators (with the required precedence), so we can just "eval" the input (which is done automatically by Input[]), but the logical negation operator doesn't work on integers (so it will remain unevaluated). If there's a !x left in the result, we replace it with 1-x.

A couple of fun facts about the evaluation:

  1. Mathematica actually also has the double factorial operator !!, which computes n*(n-2)*(n-4)*..., but applied to 0 or 1 it still gives 1, so it doesn't matter that 0!!!!! will actually be parsed as ((0!!)!!)!.
  2. Even though Mathematica leaves !0 and !1 unevaluated, it does know that ! is self-inverse, so it will automatically cancel all pairs of leading !. After the ToExpression we're always left with one of 0, 1, !0, !1.
share|improve this answer
1  
Since when was a REPL snippet allowed by default? – LegionMammal978 21 hours ago
    
@LegionMammal978 Apparently since December 2015, but I keep forgetting about it. To be fair, it's not a "snippet" in that it doesn't assume that the input is already stored somewhere in memory. And assuming the notebook environment is then not very different from having a language with implicit output. – Martin Ender 21 hours ago
    
Just curious, could a meta link be provided? (Trying to find information there is stressful, yet another problem of the SE Q&A format...) – LegionMammal978 8 hours ago
    
@LegionMammal978 it's already in the answer. – Martin Ender 3 hours ago

[Bash] + Unix utilities, 21 17 bytes

sed s/.!!*$/1/|bc

This must be saved in a file and run as a program. If you try to enter the command directly from the command line, it won't work because !! is expanded due to history substitution being enabled in bash's interactive mode. (Alternatively, you can turn history substitution off with set +H.)

Test case runs:

for x in 0 1 '0!' '1!' '!0' '!1' '!0!' '!1!' '0!!' '1!!' '!!0' '!!1' '!0!!' '!!!1' '!!!0!!!!' '!!!1!!!!'; do ./excl <<<"$x"; done

0
1
1
1
1
0
0
0
1
1
0
1
0
0
0
0
share|improve this answer
    
The old version works, this one doesn't – Kritixi Lithos 2 days ago
    
I used the TIO link – Kritixi Lithos 2 days ago
    
@KritixiLithos It worked fine when I tried it on my Linux box. The problem was apparently that TIO requires a newline at the end of the simulated input line. It's a confusing situation, so I took out the TIO link. If you want to try it out there, here's the link again (but be sure to include a newline at the end of the input if you change the input to test it out): tio.run/nexus/bash#@1@cmqJQrK@nqKilom@oX5OU/P@/… – Mitchell Spector 2 days ago
    
But what if someone has run mkdir -p 's/.!!'{bunch,of,different,directories}\$/1? Then you'll get Pathname Expansion and Sed will be attempting to read directories as though they were files, instead of reading standard input, and it won't output anything! :) – Wildcard yesterday
1  
@Wildcard I agree completely. In production scripts, I always use quotes in situations like this. (In this case, I would actually put double-quotes around the argument to sed, rather than just escaping the *. It's easier to read than using backslashes, and it avoids the possibility of missing some special character.) – Mitchell Spector yesterday

Retina, 20 15 14 bytes

Thanks to Leo for saving 1 byte.

0!
1
!!

^1|!0

Try it online!

Explanation

0!
1

Turn 0! into 1. We don't care about any other trailing !s, the resulting number is the same as if we had applied all factorials.

!!

Cancel pairs of negations. This may also cancel some factorials, but that's irrelevant.

^1|!0

Count the number of matches of this regex, which is either 1 or 0 and gives the desired result.

share|improve this answer
    
Alternate solution for same bytecount: \d.+... – Kritixi Lithos 2 days ago
    
@KritixiLithos Found a way to avoid that altogether. – Martin Ender 2 days ago
    
You can remove the ^ before !0 – Leo yesterday
    
@Leo Whoops, thank you. – Martin Ender yesterday

Grime, 14 12 9 bytes

e`\0!~\!_

Try it online!

Explanation

This matches the input against a pattern, printing 1 for match and 0 for no match.

e`\0!~\!_
e`         Match entire input against this pattern:
    !      not
  \0       a sole 0
     ~     xor
      \!   exclamation mark
        _  followed by this pattern matched recursively.

The idea is this. If the input begins with a digit, then the recursive part \!_ always fails, and \0! succeeds unless we have a single 0. Their xor succeeds unless the input is a single 0. If the input begins with a !, then \0! always succeeds, and \!_ succeeds if the recursive match succeeds. Their xor succeeds exactly when the recursive match fails, thus negating it.

share|improve this answer

Python, 44 42 bytes

Saved 2 bytes thanks to Zgarb!

lambda x:(x[-1]=='0')^len(x.rstrip('!'))%2

Step by step:

  1. x[-1]!='0'
    if x ends with 1 or !x doesn't end with 0, the factorial portion must have value 1, else 0
  2. ^len(x.rstrip('!'))%2
    exploit xor's property as a "conditional not". The condition in this case is if the length of initial !s is odd. However, .rstrip doesn't remove the number from the string so the length calculated is offset by 1, therefore the condition is inverted
  3. The offset by 1 in step 2 is corrected by changing != to == in step 1. Zgarb suggested using a difference comparison operator rather than applying another inversion, saving 2 bytes.

Try it online!

share|improve this answer
    
Fails on an input of !!0; it is currently returning 1. – Value Ink 2 days ago
    
@ValueInk should be working now – busukxuan 2 days ago
1  
lambda x:(x[-1]=='0')^len(x.rstrip('!'))%2 avoids the extra inversion. – Zgarb yesterday
    
@Zgarb Cool, thanks! – busukxuan yesterday
3  
crossed out 44 is still regular 44 – Easterly Irk yesterday

JavaScript (ES6), 43 41 29 bytes

s=>+eval(s.replace(/.!+$/,1))

Non-regex method (41 31 bytes)

Below is my initial approach. It's slightly more interesting, but significantly longer still a bit longer even after a significant optimization by Neil (10 bytes saved).

f=([c,...s])=>1/c?c|s>'':1-f(s)

Test cases

let f =

s=>+eval(s.replace(/.!+$/,1))

;[
  "0", "1", "0!", "1!", "!0", "!1", "!0!", "!1!", "0!!",
  "1!!", "!!0", "!!1", "!0!!", "!!!1", "!!!0!!!!", "!!!1!!!!"
].map(
  s => console.log(s, '=>', f(s))
)

share|improve this answer
    
I can only save 10 bytes from your non-regex method, so it's still too long: f=([c,...s])=>1/c?c|s>'':1-f(s). – Neil yesterday
    
@Neil Since it's much better than my 1st attempt anyway, I took the liberty to include your suggestion. – Arnauld yesterday

05AB1E, 9 bytes

Code:

.V¹'!ÜgG_

Uses the CP-1252 encoding. Try it online! or Verify all test cases!

Explanation:

.V         # Evaluate the input as 05AB1E code. This computes the factorial part.
   '!Ü     # Remove trailing exclamation marks..
  ¹        # ..from the first input
      g    # Get the length of the resulting string
       G   # Do the following length - 1 times:
        _  #   Negate the number
share|improve this answer

Perl, 20 bytes

19 bytes of code + -p flag.

s/\d!+/1/;$_=0+eval

Try it online!

Perl's negation returns undef or 1, so I use 0+ to numerify the result 0+undef returns 0. Besides that, not much to say about the code.

share|improve this answer
1  
Just wrote exactly this. Have a +1. – primo yesterday
    
@primo Glad to see that for once I'm not 20 bytes behind you! Thanks :) – Dada yesterday

Retina, 13 bytes

A somewhat weird approach, but it's short and it works.

0$
!1
!!

^\d

With the first two lines we replace an ending 0 with !1: with this replacement we now know that the part of our string from the digit onwards is equal to 1.

Next two lines, remove pairs of !: double negation erases itself, and we already accounted for factorial with the previous step.

Last line, match a digit at the start of the string and return the number of matches: if the negations have all been eliminated we'll find a match (and as we said before we know this is equal to 1), if there's still a negation this won't match.

Try it online!

share|improve this answer
1  
Wouldn't the final digit necessarily always be a 1? In that case, you could use 1 rather than \d. – ais523 yesterday
1  
@ais523 no, because the first part will only replace an ending 0, so for example the input 0! will stay unchanged until the last line – Leo yesterday
1  
Really lovely solution, nice work! :) – Martin Ender yesterday

Ruby, 12+1 = 39 24 15 13 bytes

Uses the -n flag. Thanks to @GB for -9 bytes!

p~/!*$|0$/%2
share|improve this answer
    
Since you only check the length, you can delete the trailing zero, instead of checking "!0" first and a single zero after that. – G B yesterday
    
@GB that's a wonderful idea! However, I found a solution that's even shorter by modifying my regex to look for the position of 0 or end-of-line – Value Ink yesterday
    
Then you could just check for trailing '!' or zero or end of line: p~/!+$|0$|$/%2 is just 14 bytes. – G B yesterday
    
And then "0$|$" could become "0?$" to save another byte. – G B 19 hours ago
1  
Better yet !*$ is shorter by two! – Value Ink 16 hours ago

Haskell, 39 bytes

f('!':b)="10"!!read[f b]
f[a]=a
f _='1'

Defines a function f, which takes a string and returns a character. Try it online!

Explanation

There are three cases: input begins with !, input has length 1, and everything else.

f('!':b)=    -- If input has head '!' and tail b,
 "10"!!      -- we index into the string "10"
  read[f b]  -- using f b converted to int. This essentially inverts f b.
f[a]=        -- If input has only one character, we know it's a digit,
 a           -- so we can just return it.
f _=         -- In all other cases, we know the input is a digit followed by !s,
 '1'         -- so we can return '1'.
share|improve this answer
    
Switch from String to Integer as the return type: f('!':b)=[1,0]!!f b;f"0"=0;f _=1. – nimi yesterday

C, 68 62 61 bytes

e(char*a){int c=1;for(;*a<34;a++)c^=1;return
a[1]?c:*a&1^!c;}

Try it online!

share|improve this answer
1  
I think you can remove the int from the function and you can change the *a==33 to *a<34. – Kritixi Lithos yesterday
    
Alas *a%2 is shorter than *a-48 – Kritixi Lithos yesterday
    
Thanks for the tip. I was also able to eliminate another character by removing the brackets around the return and assigning it. – Ahemone yesterday
    
I am pretty sure for(;*a<34;a++) can be shortened to for(;*a++<34;) saving 1 byte – Albert Renshaw yesterday
    
Unfortunately not, as the conditional statement it will always execute and so will push the pointer too far ahead for the return dereference. – Ahemone yesterday

Jelly, 5 bytes

VeMḂ$

Try it online!

Monadic function expecting a string. Inputs with leading !s cause a 1 to be printed to STDOUT along the way, so the TIO link I give is a test harness that prints the input-output pairs beneath the first line of output.

How?

VeMḂ$ - Monadic link: string
V     - eval the string
          - the implicit input of 0 causes !...! to evaluate to 1 (which gets printed),
          - the result is the evaluation of the rest: "0"=0; "0!"=1; "1"=1; "1!"=1; ...
 e    - exists in?
    $ - last two links as a monad:
  M   -     Maximal indexes - the "0" and "1" characters are greater than "!",
                            - so this results in a list of one item [i] where
                            - i is the 1-based index of the 0 or 1 character.
   Ḃ  -     %2 (vectorises) - [i%2], so a 0 if we need to logically negate and a 1 if not
                            - hence we check equality with e rather than inequality.
share|improve this answer

Haskell, 67 65 bytes

f s|foldr(\_->not)(last s`elem`"1!")$fst.span(<'0')$s="1"|1<3="0"

Try it online! Usage: f "!!!0!!!!"

Saved two bytes thanks to @nimi.

share|improve this answer

Python, 38 bytes

lambda s:(s[1::2]>s[::2])^ord(s[-1])%2

TryItOnline!

An unnamed function taking an input string s and returning an integer 0 or 1.

s[1::2] is a slice of the input string that starts at index 1 and has a step size of two:
'Like this' -> 'ieti'

s[::2] is similar but starts at the default index of 0:
'Like this' -> 'Lk hs'

The test (s[1::2]>s[::2]) checks if the 0-based index of the '0' or '1' is odd, i.e. if we need to complement.
This works because the ordering of strings is checked lexicographically with any non-empty string greater than the empty string, and with ASCII ordering, so '1'>'0'>'!'. This is a byte shorter than the simpler s.index(max(s))%2.

The ord(s[-1])%2 checks to see if the last character is not a '0' (for valid input), and results in an integer (whereas the same length (s[-1]!='0') would return a boolean).
This works because the last character of the input, s[-1], will be a '0', '1', or '!' which have ASCII code points 48, 49, and 33 respectively, which are 0, 1, and 1 modulo 2.

The ^ then performs a bitwise exclusive or operation on the two above values, returning an integer since one input, the right one, is an integer. If the left is True the complement of the right is returned, if the left is False the right is returned, as required.

share|improve this answer

Ruby, 22 21 20 bytes

->s{(s=~/!*$|0$/)%2}

Explanation:

  • First case, I got some '!' at the end, remove them, get length modulo 2.
  • Second case, no '!', if last character is zero then remove it, get length modulo 2
  • If the last character is 1, back to the first case

(-1 byte stealing @Value Ink's idea)

share|improve this answer

PHP 7.1, 58 55 54 37 bytes

Note: uses IBM-850 encoding

<?=strspn($a=$argv[1],~Ì)%2^!!$a[-1];

Run like this:

echo '<?=strspn($a=$argv[1],~Ì)%2^!!$a[-1];' | php -- '!!!1!!!!';echo
> 0

Explanation

<?=
  strspn($a=$argv[1],~Ì) # Count the number of leading exclamation marks.
  % 2                    # Make 0 (even) or 1 (odd).
  ^ !!$a[-1];            # Negate with factorial part (truthy value of the 
                         # last char):
                         # - "0" is considered falsy.
                         # - "1" or "!" is considered truthy.

Tweaks

  • Saved 3 bytes by using IBM-850 encoding
  • Saved a byte by changing the regex slighty
  • Saved 17 bytes, new version without long function names and return
share|improve this answer

Perl 6, 32 28 23 bytes

{m/(\!)*(1|0.)*/.sum%2}

How it works

{                     }  # A lambda.
{m/            /      }  # Match the lambda argument against the regex:
   (\!)*                 #   Zero or more `!`.
                         #     (First capture will be an array with one element per negation).
        (1|0.)*          #   A `1`, or a `0` and another character, zero or more times.
                         #     (Second capture will be a one-element array if the factorial
                         #     part evaluates to 1, and an empty array otherwise.)
                .sum     # Add the lengths of the two captures,
                    %2   # and return that sum modulo 2.
share|improve this answer

CJam, 12 11 bytes

r_W='0=!\~;

Try it online! Test suite (prints a 1 for each correct test case).

r      e# Read input.
_W='0= e# Duplicate and check whether the string ends in '0'. This is the
       e# only case in which the factorial part results in 0.
!      e# Negate this to get the actual result of the factorial part.
\      e# Swap with the input.
~      e# Evalute the input as CJam code. The leading `!` will apply the logical
       e# negations to the factorial result. The 0 or 1 will then push a junk value
       e# which is potentially negated a few times as well, by the factorials.
;      e# Discard the junk value.
share|improve this answer

Jelly, 8 bytes

œr”!LḂ=V

Try it online!

This is a function (monadic link) that takes one argument and returns via its return value. (It also often writes junk to standard output as a side effect, but we don't care about that.)

Explanation

œr”!LḂ=V
œr”!      Take {the input}, with all trailing ! deleted
    L     Take the length of this
     Ḃ    Take the parity of that length
      =   Return 0 if unequal, 1 if equal to:
       V    the value of {the input} when eval'ed as a niladic Jelly program

First, note that as the input always consists of some number of !, followed by a digit, followed by more !, that if we delete the trailing ! and take the length, we'll end up with one plus the number of leading ! in the program. Taking the parity of this will return 0 if there were an odd number of !, or 1 if there were an even number of !. Comparing to 0 is a "not" function, whereas comparing to 1 is the identity function; thus œr”!LḂ= effectively implements the "treat leading ! as NOT operators" part of the question.

As for the second half, handling factorials, ! is a factorial operation in Jelly, so if the program has no leading !, we can solve the problem directly with a simple eval (V). If the program does have leading !, those will be interpreted as taking the factorial of 0 (possibly multiple times), producing a return value of 1, which will be printed to standard output and discarded once a digit is seen; thus, they have no impact on the return value of the function that's my submission to the question.

share|improve this answer
    
Very nice and great explanation. – ElPedro yesterday

Haskell, 27 bytes

f('!':b)=1-f b
f"0"=0
f _=1

Try it online!

Each leading ! complements the output for the rest of the expression, done as 1-. We keep flipping until we hit a digit. If the remaining is just "0", the result is 0. Otherwise, it's a 1 or is followed by one or more !, so the result is 1.

share|improve this answer

Brainfuck - way to many bytes (232 bytes)

Clearly the wrong language for winning in code golf. Mainly I noticed a lack of anyone using this esolang. There is a good online interpreter bf interpeter or you can actually watch what the program does using this bf visualizer.

>>>>>,[>+++[<---------------->-]<<<<<<[-]+>[-]>>>>[-[<<[>+<<<<->>>[<<+>>-] ]<<[>>+<<-]<[>>+<<[-]]>>>>>[-]]<<<<<[>>>++<<<-]>+>>>>[-]]<<<<-[>>+<<[-]]>>>>,]<<->[<[-]+>[-]]<<[<[-]>>[<<+>>[-]]+<<[->>-<<]>-]>>[-]+++[<++++++++++++++++>-]<.
share|improve this answer

Java 7, 105 82 81 bytes

int a(char[]a){int b=0,c=0;for(;a[b++]<34;c^=1);return(b<a.length?1:a[b-1]&1)^c;}

Try it online!

Old regex-ish solution

int a(String a){a=a.replace("0!","1").replaceAll("1.*","1");int b=a.length()-1;return b%2^a.charAt(b)&1;}
share|improve this answer

Batch, 62 bytes

@set/ps=
@set s=%s:0!=1%
@set s=%s:!!=%
@cmd/cset/a%s:1!=1%

Takes input on STDIN. Batch actually understands leading !s correctly for this challenge, but the trailing !s need to be dealt with, which takes three steps:

  • Change 0! to 1
  • Delete pairs of !! (this is safe for the !!s before the digit too)
  • Delete any remaining trailing ! (which by now can only be after a 1)
share|improve this answer

Befunge, 24 bytes

~"!"-:#v_$1+
*+2%!.@>0~`

Try it online!

This starts by counting the number of ! characters read from stdin. The first character that isn't a ! will either be a 0 or 1, but in the process of testing for ! we will have subtracted 33, making it either 15 or 16. We then read one more character, that will either be an ! or EOF, and compare if that is less than 0 (i.e. EOF).

Taking those three data points - the exclamation count (c), the digit value, (d), and the end-of-file condition (e) - we can calculate the result as follows:

!((c + d*e) % 2)

Multiplying the digit value by the end-of-file condition means it will be converted to zero if the digit was followed by a !, thus giving it the same modulo 2 value as a 1 (which remember has been converted to 16). But before applying the modulo 2, we add the initial exclamation count, which effectively toggles the modulo 2 result as many times as their were ! prefixes. And finally we not the result since our baseline values for 0 and 1 are the opposite of what we need.

Looking at the code in more detail:

~                Read a character from stdin.
 "!"-            Subtract 33 (ASCII for '!').
     :  _        Make a duplicate and check if zero (i.e. is it a '!').
         $1+     If so, drop the duplicate, increment a counter, and repeat.
       v         Otherwise move to the second line, leaving the digit value on the stack.
       >0~`      Read one more character and check if less than 0 (i.e. EOF).
*                Multiple by the digit value, making it zero if not followed by EOF.
 +               Add to the exclamation count.
  2%             Modulo 2 the result.
    !            Then not that value.
     .@          And finally write to stdout and exit.
share|improve this answer

IBM/Lotus Notes Formula - 77 bytes

@Eval(@Left(a;@If(@Like(a;"%1%");"1";"0"))+@If(@Ends(a;"!");"1";@Right(a;1)))

There is no TIO for Notes Formula so a screenshot of all test cases is shown below:

All Test Cases

How it works

@Eval() evaluates a string as an expression

First we check if the input string in field (input) a contains 1 or 0 and take all characters to the left of whichever it is which will be a string of ! characters. We don't care how many. @Eval() will take care of that.

Next we look to see if there is a ! at the end of the string. If there is we append 1 to the ! string (0! and 1! are both 1 - it doesn't matter how many ! characters there are at the end) otherwise we append the last character unchanged because it is not a ! and could be either a 1 or a 0.

We now have a string containing the leading inversions plus a number defined by whether there are any factorial characters so we can feed this to @Eval() and get the results above.

share|improve this answer

RProgN, 31 bytes

~'(!*1?)0?(!*)'{L`x=L2%x+0>1*}R

Explained

~'(!*1?)0?(!*)'{L`x=L2%x+0>1*}R
~                               # Zero Space Segment
 '(!*1?)0?(!*)'                 # A pattern string, matching any number of !'s with optionally a 1, optionally an uncaptured 0, and any number of !'s
               {             }  # An anonymous function, which takes two arguments. The last !'s and the optional 1 with the first 1's.
                L               # Get the length of the last !'s
                 `x=            # Set 'x' to equal it.
                    L2%         # Get the length of the first !'s with the optional 1, mod 2, giving us the boolean portion.
                       x+       # Add x
                         0>1*   # If the total is larger than 0, converted to a number. If there are any leading !'s, this will always be 1, otherwise, it will be the boolean of the left handside.
                              R # Replace the input string via the function matching the first pattern.

Try it online!

share|improve this answer

Bean, 24 bytes

Hexdump:

00000000 26 4a c1 53 a0 17 53 d0 80 a0 5d 20 80 0a a1 80  &JÁS .SÐ. ] ..¡.
00000010 81 00 25 3a ae a1 ab 24                          ..%:®¡«$
00000018

Equivalent JavaScript:

+eval(a.replace(/.!+$/,1))

Sorry for stepping on your toes, Arnauld.

Explanation:

Takes first line of input as unformatted string in a, and replaces any digit followed by one or more ! with 1, so that the rest can be eval'd by JavaScript.

Try the demo, or the test suite

share|improve this answer

Haskell, 43

There must be a better way to do this...

f (h:t)|h=='!'=1-f t|h=='1'=1|t==[]=0|1<2=1
share|improve this answer

Pyth, 13 bytes

Code

s.v:z"\d!+""1

There may be a way to shave off a couple of bytes, but alas.

Explanation

s                # Cast to an integer (Python's int()).
 .v              # Evaluate (Python's eval()). This handles the negations.
   :             # Regex substitution. The following three expressions are its arguments.
    z            # Argument 1: what to replace in. This is equal to the (unevaluated) input string.
     "\d!+"      # Argument 2: what to replace. This is a regex that matches a number followed by one or more !'s.
           "1    # Argument 3: what to replace to. The string "1" (ending quote not needed in Pyth).

You can check it out here or run the test suite here. I have no earthly idea how to (or if one actually can) use the test suite feature to run tests as opposed to just evaluating a bunch of inputs at once, but if someone else knows, I'm all ears.

share|improve this answer

protected by Community yesterday

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.