68
\$\begingroup\$

Doing code review, I stumbled upon the following code, that tests the status of a checkbox:

if (!isNotUnchecked()) { ... }

I had to brainstorm for 30 minutes to find out what actual checkbox status the code was expecting. Please write me a program that can simplify these silly expressions!


The program should accept as input a string representing the expression to simplify (for example: !isNotUnchecked()). The program should output a logically equivalent simplified expression, either isChecked() or !isChecked().

The method name in the input expression always starts with is, contains 0..n Not, and ends with Checked() or Unchecked(). The method can be prefixed by any number of !.

Examples

isChecked() => isChecked()
isUnchecked() => !isChecked()
isNotChecked() => !isChecked()
!isNotChecked() => isChecked()
!!!isNotNotUnchecked() => isChecked()
\$\endgroup\$
7
  • \$\begingroup\$ Is the text always case-sensitive? Would the input be notunischecked? \$\endgroup\$
    – stevefestl
    May 11, 2017 at 9:50
  • 1
    \$\begingroup\$ @SteveFest No, you can assume the input is always in the format that I've described above. You don't need to handle isnotunchecked for example. \$\endgroup\$
    – Arnaud
    May 11, 2017 at 12:14
  • 7
    \$\begingroup\$ With a function name like that I'd give it 10 to 1 odds that it didn't even actually test the checked condition consistent with it's naming. \$\endgroup\$
    – Caleb
    May 12, 2017 at 11:34
  • 2
    \$\begingroup\$ In other words, you know what is an unchecked box, you know what is a non-unchecked box (it is checked, if and only if "checked" and "unchecked" are the only two possible states, otherwise it could be anything in the checkbox: int, sign...) and for this specific checkbox, it is not (it is not "checked", whether it is with a check mark or anything). If true then, you are sure that the checkbox is not "checked" by anything. If false, well, you know the checkbox is a non-unchecked box but it doesn't necessarily mean it is checked unless there are only two possible states (then it is checked). \$\endgroup\$
    – J Doe
    Jun 24, 2017 at 12:47
  • 1
    \$\begingroup\$ @J Doe thanks for clarification! \$\endgroup\$
    – Arnaud
    Jun 24, 2017 at 21:11

28 Answers 28

32
\$\begingroup\$

Python, 51 bytes

lambda s:sum(map(s.count,'!NU'))%2*'!'+'isC'+s[-8:]

Try it online!

\$\endgroup\$
6
  • \$\begingroup\$ You are a pure genius! Would have never thought of s[-8:] \$\endgroup\$
    – Mr. Xcoder
    May 11, 2017 at 11:43
  • \$\begingroup\$ Surely 'isC'+s[-8:] is a byte longer than 'isChecked'? \$\endgroup\$
    – Neil
    May 11, 2017 at 13:25
  • 10
    \$\begingroup\$ but 1 byte shorter than 'isChecked()' \$\endgroup\$ May 11, 2017 at 13:29
  • \$\begingroup\$ Can someone explain what s[-8:] is/does? \$\endgroup\$
    – ESR
    May 12, 2017 at 0:08
  • 1
    \$\begingroup\$ @EdmundReed It takes the last 8 characters of the input, which are always hecked(). \$\endgroup\$
    – xnor
    May 12, 2017 at 0:09
24
\$\begingroup\$

Retina, 23 bytes

Unc
!C
Not
!
O`is|!
!!

Try it online!

Explanation

Unc
!C

Turn Unchecked into !Checked.

Not
!

Turn all Nots into !. We now get something like !!!is!!!!Checked().

O`is|!

Sort all matches of either is or !. Since ! < is, this moves all the ! to the beginning of the string, so the above example would become !!!!!!!isChecked().

!!

Remove pairs of ! to cancel repeated negation.

\$\endgroup\$
14
\$\begingroup\$

///, 26 bytes

/Unc/NotC//isNot/!is//!!//

Try it online!

Port of my Retina answer.

\$\endgroup\$
13
\$\begingroup\$

Python, 43 bytes

lambda s:sum(map(ord,s))%2*'!'+'isC'+s[-8:]

An unnamed function taking the string, s and returning a string.

Try it online!

No need to check for existence of characters when !, Not, and Un all have exactly one odd ordinal (and c and C are both odd), so just sum up the ordinals and use the value modulo 2 to decide if we want a ! or not.

Other than that the form is the same as xnor's answer, as I didn't find anything better. The following is also 43:

lambda s:'!isC'[~sum(map(ord,s))%2:]+s[-8:]
\$\endgroup\$
10
\$\begingroup\$

JavaScript (ES6), 51 50 bytes

f=
s=>(s.split(/!|n/i).length%2?'':'!')+'isChecked()'
<input oninput=o.textContent=f(this.value)><pre id=o>

Works by looking for !, N, and n characters, which invert the checked state. split returns an odd array length by default, so we add the ! when the split length is even. Edit: Saved 1 byte thanks to @ETHproductions. Alternative version, also for 50 bytes:

s=>`${s.split(/!|n/i).length%2?``:`!`}isChecked()`
\$\endgroup\$
7
  • \$\begingroup\$ Huh, now I go back and look at the other answers, they're all doing this. \$\endgroup\$
    – Neil
    May 11, 2017 at 8:05
  • \$\begingroup\$ You should be able to drop the global flag from the RegEx to save a byte. \$\endgroup\$
    – Shaggy
    May 11, 2017 at 8:10
  • \$\begingroup\$ @Shaggy Actually my length is correct, I just failed to removed the g in the latest edit. \$\endgroup\$
    – Neil
    May 11, 2017 at 8:33
  • 1
    \$\begingroup\$ I think you can save a byte with /!|N/i \$\endgroup\$ May 11, 2017 at 11:19
  • \$\begingroup\$ @ETHproductions I think you meant /!|N/ without the i modifier \$\endgroup\$
    – SplittyDev
    May 12, 2017 at 12:36
9
\$\begingroup\$

Retina, 24 bytes

Unc
NotC
+`isNot
!is
!!

Try it online!

\$\endgroup\$
0
7
\$\begingroup\$

Java 7, 100 77 bytes

String c(String s){return(s.split("[!NU]").length%2<1?"!":"")+"isChecked()";}

Expanation:

String c(String s){  // Method with String parameter and String return-type
  return(s.split("[!NU]").length
                     //  Count the amount of '!', 'N' and 'U' in the input String (+ 1)
    %2<1?            //  and if they are an even number:
     "!"             //   Start with an examination mark
    :                //  Else:
     "")             //   Start with nothing
    +"isChecked()";  //  And append "isChecked()" to that
}                    // End of method

Test code:

Try it here.

class M{
  static String c(String s){return(s.split("[!NU]").length%2<1?"!":"")+"isChecked()";}

  public static void main(String[] a){
    System.out.println(c("isChecked()"));
    System.out.println(c("isUnchecked()"));
    System.out.println(c("isNotChecked()"));
    System.out.println(c("!isNotChecked()"));
    System.out.println(c("!!!isNotNotUnchecked()"));
  }
}

Output:

isChecked()
!isChecked()
!isChecked()
isChecked()
isChecked()
\$\endgroup\$
7
\$\begingroup\$

Aceto, 49 bytes

&M"pp"
L!)(de
&c;`Che"
`!d!sick
!',@p"!'
'N'U`!Lu

yadda yadda Hilbert curve.

First of all, we push the three important characters on the stack:

!'
'N'U

Then we set a catch mark and start by reading a single character. We duplicate it and negate it, and if the result of this is truthy (so if the string was empty; so the input ended), we jump to the end:

;`
d!
,@

With the remaining copy of the input character, we check whether it is contained in the rest of the stack (i.e. if its one of !, N, U). If it's not, we raise an error, throwing us back to our catch mark where we read another character:

&c
`!

Otherwise, we load what's on quick storage (essentially a register that's initially an empty string; falsy), negate it and send it back to quick storage, then raise the error too (going back to reading characters):

&M
L!

When the input stopped, we are sent to the end. There, we reverse the direction, push an exclamation mark, and load quick storage and negate it. If that is truthy (i.e. we've had an odd number of negation things), we print the exclamation mark we've pushed:

p !'
`!Lu

Finally, we push the string in two parts and print them (for space saving reasons):

"pp"
)(de
  Che"
  sick
   "

Afterwards, the program still runs back to the original beginning, but since none of the commands output anything or have loopy behaviour, that doesn't matter. Actually, the first non-nopping command we reach raises an exception, skipping a majority of the code because we jump to the catch mark, meaning all Aceto sees in that part is:

&



!' @
'N'U

Since U is now not preceeded by a single-quote character and is therefore not seen as a character literal, it gets interpreted as a command: U reverses all the elements on the stack (now it's !, N, U, from the top), and 'N and '! push more characters, meaning we end with the stack [U, N, !, N, !].

Side note: This is the first Aceto program written (in part) with the help of Aceto's new editor.

\$\endgroup\$
6
\$\begingroup\$

C, 78 70 68 Bytes

Thank you Christoph!

c;f(char*s){for(c=1;*s;)c^=!!strchr("!NU",*s++);s="!isChecked()"+c;}

Try it online

Output:

isChecked() => isChecked()
isUnchecked() => !isChecked()
isNotChecked() => !isChecked()
!isNotChecked() => isChecked()
!!!isNotNotUnchecked() => isChecked()
\$\endgroup\$
1
  • 1
    \$\begingroup\$ c;f(char*s){for(c=1;*s;)c^=!!strchr("!NU",*s++);s="!isChecked()"+c;} using xor to flip c saves 2 byte. \$\endgroup\$
    – Christoph
    May 11, 2017 at 11:23
6
\$\begingroup\$

Perl 5, 31 bytes

-2 bytes thanks to @Dom Hastings.

30 bytes of code + -p flag.

/c/i;$_="!"x(y/UN!//%2).isC.$'

Try it online!

y/UN!// counts the number of occurrences of Un, Not, and !. The result is that many ! modulo 2, followed by isChecked().


Another attempt, based on regex, for 38 bytes (Dom Hastings saved 1 byte on that one):

s/isNot|isUn(c)/!is\u$1/?redo:s/!!//g

Try it online!

\$\endgroup\$
6
  • \$\begingroup\$ Your regex version doesn't work because there are two cs in Unchecked. \$\endgroup\$
    – Neil
    May 11, 2017 at 8:39
  • 1
    \$\begingroup\$ @Neil the regex only replaces the first one (since I'm not using /g flag). The test cases look good to me (cf the TryItOnline link). So I don't really see what you mean... \$\endgroup\$
    – Dada
    May 11, 2017 at 9:11
  • \$\begingroup\$ Sorry, the correct reason that your regex version doesn't work is that although there is a c in Unchecked there is also one in Checked, so when you subsitute it you end up with CheCked. \$\endgroup\$
    – Neil
    May 11, 2017 at 9:30
  • 1
    \$\begingroup\$ Hey, hope you're doing alright! I haven't been here in a while, but I've had a little play with these for -2 on the first and -1 on the second \$\endgroup\$ May 12, 2017 at 7:47
  • 1
    \$\begingroup\$ @DomHastings Hey! Awesome, thanks a lot! Happy to see you back around :-) \$\endgroup\$
    – Dada
    May 12, 2017 at 8:25
6
\$\begingroup\$

Scala, 39 30 bytes

s=>"!"*(s.sum%2)+"isChecked()"

Try it online!

Unfortunately I couldn't get it to deduce the type of s.

Edit: Moved the type declaration to the header (I think this is allowed, if not I'll put it back).

\$\endgroup\$
5
\$\begingroup\$

Ruby, 40 bytes

->x{?!*(x.count('!UN')%2)+'isChecked()'}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to PPCG! Nice answer. :) \$\endgroup\$ May 11, 2017 at 19:19
  • \$\begingroup\$ @MartinEnder thanks! \$\endgroup\$
    – Alex
    May 11, 2017 at 19:31
3
\$\begingroup\$

05AB1E, 22 bytes

…Unc„!C:'€–™'!:'!†„!!K

Try it online!

\$\endgroup\$
3
\$\begingroup\$

05AB1E, 16 bytes

ÇOÉ'!×…isCyR8£RJ

Try it online!

Uses the trick of summing the ordinals from Jonathan Allan's python answer.

Explanation

 ÇO                # sum of ascii values of input
   É               # is odd
    '!×            # repeat "!" that many times
       …isC        # push the string "isC"
           IR8£R   # push the last 8 chars of input
                J  # join everything to string
\$\endgroup\$
3
\$\begingroup\$

Japt, 24 23 bytes

o"!N" l u)ç'! +`‰C”×B()

Explanation

 o"!N" l u)ç'! +`‰C”×B()
Uo"!N" l u)ç'! +`‰C”×B()`
Uo"!N"                     # Only keep "!", "n" and "N" from the input
           ç'!             # Repeat the string "!" by
       l u)                # the parity of the length of the newly formed string
               +`‰C”×B()` # and concatenate with the string "isChecked()"

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Wait... How does... Why... Is o case-insensitive? I did not know that... \$\endgroup\$ May 11, 2017 at 14:50
  • \$\begingroup\$ I didn't know it either, but I found out when I tested with "!NU". The lowercase "n" in "Unchecked" also remained, so I could drop the "U" : ) \$\endgroup\$
    – Luke
    May 11, 2017 at 15:07
3
\$\begingroup\$

PHP (5.5 - 5.6), 52 50 49 Bytes

<?='!'[count(spliti('!|N',$argn))%2]?>isChecked()

Try it here.

-2 Bytes by @Titus. Ty :)
-1 Byte  by @ETHproductions. Ty :)

PHP (>=5.5), 66 65 61

for($b=b;$a=$argn[$i++];)$b^=$a;echo$b&"!"|" ","isChecked()";

Without regex it gets a bit more compex :) Try it here.

-4 Bytes by @Titus. Ty :)
\$\endgroup\$
5
  • 1
    \$\begingroup\$ error_reporting default value is E_ALL&~E_NOTICE&~E_STRICT&~E_DEPRECATED. \$\endgroup\$
    – Titus
    May 11, 2017 at 11:20
  • 1
    \$\begingroup\$ @Titus beating JS in a regex challenge yay! \$\endgroup\$
    – Christoph
    May 11, 2017 at 11:34
  • \$\begingroup\$ $b^=$a Very nice find! You can also do that without the PHP tags at the same size. \$\endgroup\$
    – Titus
    May 11, 2017 at 17:43
  • 1
    \$\begingroup\$ 61 bytes if leading whitespace is allowed: for($b=b;$a=$argn[$i++];)$b^=$a;echo$b&"!"|" ","isChecked()"; \$\endgroup\$
    – Titus
    May 11, 2017 at 17:57
  • \$\begingroup\$ @Titus I have to admit that it was inspired by this answer. \$\endgroup\$
    – Christoph
    May 11, 2017 at 20:08
3
\$\begingroup\$

Jelly,  16  15 bytes

OSḂ⁾!iṫ⁾sCø³ṫ-7

A full program that takes the string as a command line argument and prints the result

Try it online!

OSḂ⁾!iṫ-7³ṫṭ⁾sC or OSḂ⁾!iṫ-7³ṫ⁾sC; would both also work for 15.

How?

Uses the same idea as my Python answer, but saves bytes using a different construction of !isC or isC and some implicit printing in Jelly...

OSḂ⁾!iṫ⁾sCø³ṫ-7 - Main link: s
O               - cast to ordinals
 S              - sum
  Ḃ             - mod 2
   ⁾!i          - literal ['!','i']
      ṫ         - tail -> ['i'] if OSḂ was 0; ['!','i'] if OSḂ was 1
                - this is printed due to the following starting a new leading
                - constant chain. Printing smashes so either "i" or "!i" is printed.
       ⁾sC      - literal ['s','C']
                - this is printed (as "sC") due to the following niladic chain.
          ø     - start a new niladic chain
           ³    - program's first input (3rd command line argument), s
            ṫ-7 - tail from index -7 = ['h','e','c','k','e','d','(',')']
                - implicit print (of "hecked()")

previous @ 16 bytes 9 (using concatenation and pairing with the same underlying idea):

OSḂ⁾!iṫ;⁾sC,ṫ€-7
\$\endgroup\$
1
  • \$\begingroup\$ Ah, darn, I thought I was on to something with the mod 2 trick. Then I found this :P I had this for 18 bytes, maybe it could help: OS1&”!x;“isC”;ṫ-7$ \$\endgroup\$ May 11, 2017 at 14:46
2
\$\begingroup\$

Perl 6,  35  31 bytes

{'!'x m:g/<[!NU]>/%2~'isChecked()'}

Try it

{'!'x tr/!NU//%2~'isChecked()'}

Try it
(requires mutable input string which will be mutilated)

Expanded:

{
  #(
    '!'
  x               # string repeat

    # m:g/<[!NU]>/
    tr/!NU//      # find the number of negatives
      % 2         # modulus 2
  #)

  ~                # string concat

    'isChecked()'
}
\$\endgroup\$
2
\$\begingroup\$

Sed, 36 Bytes

Same idea as all the other direct substitution answers.

:
s/Unc/NotC/
s/isNot/!is/
s/!!//
t
\$\endgroup\$
2
\$\begingroup\$

sed, 37 38 bytes

:;s/is(Not|Un)/!is/;s/!!//;t;s/ch/Ch/

37 + 1 for -r switch:

sed -r ':;s/is(Not|Un)/!is/;s/!!//;t;s/ch/Ch/'
\$\endgroup\$
4
  • 1
    \$\begingroup\$ That last s/c/C/ caused problems for the Perl 5 answer... \$\endgroup\$
    – Neil
    May 11, 2017 at 13:27
  • \$\begingroup\$ Yeah, looks like the s/c/C/ is catching the second "c" in cases without "Un" \$\endgroup\$
    – Kevin
    May 11, 2017 at 17:48
  • 1
    \$\begingroup\$ Also, you can save a byte by dropping the g and moving the s/!!// inside the loop. \$\endgroup\$
    – Kevin
    May 11, 2017 at 17:49
  • \$\begingroup\$ You don't need the switch to get 37 bytes \$\endgroup\$
    – Philippos
    Nov 28, 2023 at 9:47
2
\$\begingroup\$

Mathematica, 82 61 60 Bytes

Small tweak, added one more infix operator:

"!"~Table~Mod[#~StringCount~{"o","n","!"},2]<>"isChecked()"&

Previously:

"!"~Table~Mod[StringCount[#,{"o","n","!"}],2]<>"isChecked()"&

Count up all the o's, n's and !'s then mod 2 and put that many ! in front.

Old version:

"!"~Table~Mod[StringCount[StringReplace[#,{{"o","n"}->"!"}],"!"],2]<>"isChecked()"&
\$\endgroup\$
2
\$\begingroup\$

Excel, 90 bytes

=IF(ISODD(SEARCH("C",SUBSTITUTE(SUBSTITUTE(A1,"Un","!"),"Not","!"))),"","!")&"isChecked()"
\$\endgroup\$
2
\$\begingroup\$

Windows Batch, 120 bytes

Previously 268 257 253 245 239 221 182 176 169 123 bytes

@set a=%1
@set s=#%a:~,-2%
@set s=%s:!=N#%
@for %%a in (%s:N= %)do @set/ac+=5
@if %c:~-1%==0 cd|set/p=!
@echo isC%a:~-8%

The programs replaces all the ! into N#. Because now all negation signs, !(Now it is N#), Not, and Un contains N, the program can counts the number of appearance of N and determines if an leading ! is required.

Each time the program counts an N, the counter is added by 5. The reason for adding 5 is because each alternating values when adding 5 ends in either 0 or 5. This can be used to determine whether the value is odd or even and the leading ! us added if required.

In addition, xnor's last-eight-character trick is utilized.

\$\endgroup\$
2
  • \$\begingroup\$ One would think programming in windows batch would be impossible... \$\endgroup\$
    – Maya
    May 12, 2017 at 17:03
  • \$\begingroup\$ Of course...... Batch scripting is absurd.... \$\endgroup\$
    – stevefestl
    May 12, 2017 at 22:57
1
\$\begingroup\$

Jelly, 29 28 25 21 bytes

f“NU!”LḂ”!x;“µịÆẹṠƊẹ»

Try it online!

f“NU!”LḂ”!x;“µịÆẹṠƊẹ»  Main link, argument is z
f“NU!”                 Filter to only keep "NU!"
      LḂ”!x            Repeat exclamation mark by the parity of the length
           ;“µịÆẹṠƊẹ»  Concatenate to "isChecked()"

-4 bytes thanks to Jonathan Allan!
-4 bytes thanks to Jonathan Allan! (by using compressed strings)

\$\endgroup\$
2
  • \$\begingroup\$ Save the interface Lynn made here as a module (say jellyCompress.py), then that would have been formed with jellyCompress.Compress().string("is").dictionary("Checked").string("()").go(). (If you're running in a Windows cmd install and switch to the font DejaVu Sans Mono and change the codepage with the command chcp 65001 before launching Python to get the characters to display) \$\endgroup\$ May 11, 2017 at 14:25
  • \$\begingroup\$ @JonathanAllan Oh okay. Thanks! \$\endgroup\$
    – hyper-neutrino
    May 11, 2017 at 14:35
1
\$\begingroup\$

PHP, 55 Bytes

<?=preg_match_all("#!|N#i",$argn)&1?"!":""?>isChecked()

Try it online!

PHP, 58 Bytes

<?=preg_match_all("#[!NU]#",$argn)%2?"!":"","isChecked()";

instead "#[!NU]#" you can use "#[!N]#i"

Try it online!

PHP, 68 Bytes

Version without Regex

for(;$c=$argn[$i++];)$d^=!trim($c,"UN!");echo"!"[!$d],"isChecked()";

Try it online!

\$\endgroup\$
8
  • 3
    \$\begingroup\$ <?=preg_match_all("#[!UN]#",$argn)&1?"!":""?>isChecked() -2 bytes \$\endgroup\$
    – Titus
    May 11, 2017 at 11:18
  • \$\begingroup\$ Had exactly the same answer before I came up with count(split()) :D @Titus nice idea ! \$\endgroup\$
    – Christoph
    May 11, 2017 at 11:30
  • 1
    \$\begingroup\$ " !"[$d&1] saves another byte if leading whitespace is ok. $d^=!trim($c,"UN!") saves 3 bytes (because you need no &1 anymore). \$\endgroup\$
    – Titus
    May 11, 2017 at 15:42
  • 1
    \$\begingroup\$ @Titus Yes one example more that you have more knowledge then myself. Thank You and for the trailing whitespace problem I have make "!"[!$d] instead \$\endgroup\$ May 11, 2017 at 16:01
  • 1
    \$\begingroup\$ @Christoph you are right I have forget it sorry about that \$\endgroup\$ May 11, 2017 at 17:08
1
\$\begingroup\$

Japt, 19 bytes

`‰C”×B()`i'!pU¬xc u

Try it online!

Unpacked & How it works

`‰C”×B()`i'!pUq xc u

`‰C”×B()`   Compressed string for "isChecked()"
i     Insert the following string at the beginning...
'!p     "!" repeated the following number of times...
Uq        Split the input into chars
xc        Sum the charcodes
u         Modulo 2

Using the charcode-sum trick from Jonathan Allan's Python solution.

\$\endgroup\$
1
\$\begingroup\$

Pascal (FPC), 119 bytes

var s:string;j:word;c:char;begin read(s);for c in s do j:=j+ord(c);if 1=j mod 2then write('!');write('isChecked()')end.

Try it online!

Using method that almost every answer does, summing codepoints of characters in the input, then checking parity of the sum.

\$\endgroup\$
1
\$\begingroup\$

ReRegex, 32 bytes

/!!//Not/!/Unc/!C/is!/!is/#input

Explained

Works like the Retina answer

/!!//                            #Remove all !! pairs
     Not/!/                      #Replace all Nots with !s
           Unc/!C/               #Replace any Unc's with !C (Turning Unchecked into !Checked)
                  is!/!is/       #Float all !'s past the is to the left
                          #input #Take the stdin as input

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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