15
\$\begingroup\$

Disclaimer: This isn't my challenge but ThisGuy said I was OK to post.


Occasionally I want to make a word into it's opposite, like happiness goes to unhappiness. Unfortunately when this happens, my brain will sometimes go blank. Then one day, after yet another this happening, I thought to my self "This is what programs are for!"

As the English language has many exceptions, I have created a list which contains the prefix for the starting letter

q or h -> dis- (honest -> dishonest) l -> il- (legal -> illegal) m or p -> im- (mature -> immature) r -> ir- (responsible -> irresponsible) everything else -> un- (worthy -> unworthy) 

Task

Given an input as a string, make the string into its negative and output the result. You can assume that all the inputs given will fit the above rules. Submissions may be programs or functions, not snippets.

Input

A single string, taken either as a parameter or from STDIN

Output

The negated form of that string, conforming to the above rules

How to Win

This is a so shortest code wins

\$\endgroup\$
9
  • 4
    \$\begingroup\$ Can we assume we'll never get a word that starts with a q without a u? \$\endgroup\$ Commented Apr 5, 2017 at 20:06
  • 3
    \$\begingroup\$ Off the top of my head, qadi, qat, the aforementioned qi, qirsh, and qwerty. (I play a lot of Scrabble) \$\endgroup\$ Commented Apr 5, 2017 at 20:23
  • 4
    \$\begingroup\$ @wsbltc Well, there's a fair few, but they're pretty much all borrowed words from other languages so questionable whether they really count as English. So can we assume that a q is always followed by a u in the string or not? \$\endgroup\$ Commented Apr 5, 2017 at 20:24
  • 3
    \$\begingroup\$ Yes you can assume it always has a u \$\endgroup\$ Commented Apr 5, 2017 at 20:48
  • 12
    \$\begingroup\$ This challenge could make a pedant quite dishappy... \$\endgroup\$ Commented Apr 6, 2017 at 10:08

20 Answers 20

10
\$\begingroup\$

Python, 55 bytes

lambda n:'ddiiiiuiimmlrnss'[5-'rlmphq'.find(n[0])::7]+n 

Try it online!


We need to handle 7 different starting letters:
g -> dis, h -> dis, p -> im, m -> im, l -> il, r -> ir and everything else -> un

We can store all these negations in a single string and extract the right one through slicing:

 d i s d i s i m i m i l i r u n 'ddiiiiuiimmlrnss'[i::7] 

Now we need to calculate the start index i. 'rlmphq'.find returns 0 for 'r', 5 for q and -1 for everything not contained in the string. To get the needed value from 0 to 6 we still need to subtract the return value from 5, resulting in this code:

'ddiiiiuiimmlrnss'[5-'rlmphq'.find(n[0])::7] 
\$\endgroup\$
3
  • \$\begingroup\$ That's really cute! \$\endgroup\$ Commented Apr 6, 2017 at 10:59
  • \$\begingroup\$ Can someone explain how the hell is this works? I understand what's going on with the slice notation, but what are the magic strings ddiiiiuiimmlrnss and rlmphq and the number 5 for, why is the slice skip 7? \$\endgroup\$ Commented Apr 6, 2017 at 19:51
  • \$\begingroup\$ @Keatinge added an explanation. I hope it helps you \$\endgroup\$ Commented Apr 6, 2017 at 20:52
6
\$\begingroup\$

GNU sed, 50 bytes

Includes +1 for -r

s/^q|^h/dis&/ s/^l|^r|^m/i&&/ s/^p/imp/ t s/^/un/ 

Nothing fancy. Uses & in the replacement to combine a few substitutions, and t to skip the last one if one of the first substitutions happens.

Try it online!

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

Jelly, 30 bytes

1ị“qmlrrhp”iị“3bµWI⁼ṡ÷ʠ$»œs5¤; 

Try it online!

How?

1ị“qmlrrhp”iị“3bµWI⁼ṡ÷ʠ$»œs5¤; - Main link: string 1ị - 1 index into the string (first character of the string) i - 1-based index of 1st occurrence of that in (else zero): “qmlrrhp” - char list "qmlrrhp" ị - index into (1-based and modulo): ¤ - nilad followed by link(s) as a nilad: “3bµWI⁼ṡ÷ʠ$» - compressed string "dis"+"imili"+"run"="disimilirun" œs5 - split "equally" into 5: ["dis","im","il","ir","un"] ; - concatenate with the string 

Note that the repeated r in “qmlrrhp” is in the 5th index, which, if referenced, would result in prepending un, so it could equally well be anything other than h or p.

\$\endgroup\$
4
\$\begingroup\$

TI-Basic, 104 bytes

Prompt Str0 sub(Str0,1,1→Str2 Str0 If Str2="Q" or Str2="H "DIS"+Ans If Str2="L "IL"+Ans If Str2="M" or Str2="P "IM"+Ans If Str2="R "IR"+Ans If Ans=Str0 "UN"+Ans Ans 

Requires all capital letters.

Explanation:

Prompt Str0 # 4 bytes, input user string to Str0 sub(Str0,1,1→Str2 # 12 bytes, store first character in Str2 Str0 # 3 bytes, store Str0 in Ans If Str2="Q" or Str2="H # 14 bytes, if the first letter was Q or H "DIS"+Ans # 8 bytes, store DIS+Ans in Ans If Str2="L # 7 bytes, If the first letter was L "IL"+Ans # 7 bytes, store IL+Ans in Ans If Str2="Q" or Str2="H # 14 bytes, if the first letter was Q or H "IM"+Ans # 7 bytes, store DIS+Ans in Ans If Str2="R # 7 bytes, if the first letter was R "IR"+Ans # 7 bytes, store IR+Ans in Ans If Ans=Str0 # 6 bytes, if Ans has not been changed (first letter was none of the above) "UN"+Ans # 7 bytes, store UN+Ans in Ans Ans # 1 byte, implicitly return Ans 
\$\endgroup\$
1
  • \$\begingroup\$ 81 bytes \$\endgroup\$ Commented Jun 6, 2021 at 22:08
4
\$\begingroup\$

///, 59 56 bytes

/^/\/\/#//#qu/disqu^h/dish^l/ill^m/imm^p/ipp^r/irr^/un/# 

Try it online!

Input goes after the very last #.

How it works:

I made an optimization that reduced the size to 56 bytes, but since that complicates things I will explain the original version, then explain the golf.

/#qu/disqu//#h/dish//#l/ill//#m/imm//#p/ipp//#r/irr//#/un/# |everything after the ` |` is not code. /#qu/disqu/ |replace `qu` with `disqu` /#h/dish/ |replace `h` with `dish`. /#l/ill/ |replace `l` with `ill`. /#m/imm/ |replace `m` with `imm`. /#p/ipp/ |replace `p` with `ipp`. /#r/irr/ |replace `r` with `irr`. /#/un/ |replace everything else with `un`. # |safety control 

Intuition: The challenge is simple enough, just add the negative depending on the beginning of the word. However, in ///, you cannot just concatenate if [...], you can only replace something following a specific pattern. So in this program, the positive word beginnings are replaced with the negative word beginnings. The # was added to make sure that once a new beginning was added, no more new beginnings would be added. The # also made it possible to do 'everything else: un'.

The golf incorporates a new substitution at he beginning: /^/\/\/#/. This replaces all ^ with //#, which was a common pattern in the original version.

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

Batch, 114 bytes

@set/pw= @set p=un @for %%p in (dis.q dis.h il.l im.m im.p ir.r)do @if .%w:~,1%==%%~xp set p=%%~np @echo %p%%w% 

Checks the first character of the word against the list of custom prefixes and if so changes the prefix from the default of un. Special-casing qu is possible at a cost of 21 bytes.

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

Javascript, 72 71 66 61 60 59 bytes

w=>('dis....il.im...im.dis.ir'.split('.')[w.charCodeAt(0)-104]||'un')+w

w=>'un.dis.dis.il.im.im.ir'.split('.')['qhlmpr'.indexOf(w[0])+1]+w

Yeah, it's still longer than an existing solution. :)

w=>['un','dis','im','il','ir']['qmlrhp'.search(w[0])%4+1]+w 

In case this needs any explanation, I'm taking advantage of the q/h and m/p pairs by combining their index in the search string with a mod 4, then using that as the lookup into the prefix array.

\$\endgroup\$
2
  • \$\begingroup\$ Great answer. Save 1 byte using search instead of indexOf. And some more, I think, using & instead of % \$\endgroup\$ Commented Apr 6, 2017 at 10:53
  • \$\begingroup\$ Thank you! I didn't know about search. Can't see how to make the & trick work - would be perfect if my array was only 4 elements. \$\endgroup\$ Commented Apr 6, 2017 at 11:07
3
\$\begingroup\$

JavaScript (71 64 61 bytes)

w=>({q:a='dis',h:a,l:'il',m:b='im',p:b,r:'ir'}[w[0]]||'un')+w

Edits:

  • Saved 7 bytes thanks to @ErtySeidohl (charAt(0) -> [0])
  • Saved 3 bytes thanks to @edc65 (assigning shared prefixes to variables)

var f = w=>({q:a='dis',h:a,l:'il',m:b='im',p:b,r:'ir'}[w[0]]||'un')+w; function onChange() { var word = event.target.value; var output = f(word); document.getElementById('output').innerHTML = output; }
Input Word: <input type='text' oninput='onChange()'/><br/> Output Word: <span id="output">

\$\endgroup\$
5
  • 1
    \$\begingroup\$ If you don't care about backward compatibility with IE7, couldn't you use w[0] instead of w.charAt(0)? \$\endgroup\$ Commented Apr 6, 2017 at 2:21
  • \$\begingroup\$ @ErtySeidohl Thanks! Just learned something new ;-) \$\endgroup\$ Commented Apr 6, 2017 at 4:41
  • \$\begingroup\$ I'm new here, but is it legitimate to provide an answer starting with just w=>...? The actual function definition would include let f=w=>... ? (Probably covered in an FAQ somewhere...) \$\endgroup\$ Commented Apr 6, 2017 at 7:10
  • \$\begingroup\$ @SteveBennett yes it's legitimate. Naming the function is not relevant \$\endgroup\$ Commented Apr 6, 2017 at 10:32
  • 1
    \$\begingroup\$ w=>({q:a='dis',h:a,l:'il',m:b='im',p:b,r:'ir'}[w[0]]||'un')+w 3 bytes less \$\endgroup\$ Commented Apr 6, 2017 at 10:52
2
\$\begingroup\$

Haskell, 71 bytes

f l=maybe"un"id(lookup(l!!0)$zip"qhlmpr"$words"dis dis il im im ir")++l 

Usage example: f "legal"-> "illegal". Try it online!

Build a lookup table of prefix/replacement pairs for looking up the first char of the input string with a default value of "un" if not found.

\$\endgroup\$
2
\$\begingroup\$

Mathematica, 107 bytes

StringReplace[StartOfString~~x:#:>#2<>x&@@@{{"q"|"h","dis"},{"l","il"},{"m"|"p","im"},{"r","ir"},{_,"un"}}] 

Explanation:

StartOfString~~x:#:>#2<>x& is a pure function where the first argument is a string pattern to match at the beginning of the string and the second argument is a string to prepend to the match. It returns a delayed rule suitable for use within StringReplace. This is then applied to each of the pairs {{"q"|"h","dis"},{"l","il"},{"m"|"p","im"},{"r","ir"},{_,"un"}} resulting in the list of rules

{ StartOfString~~x:"q"|"h":>"dis"<>x, StartOfString~~x:"l":>"il"<>x, StartOfString~~x:"m"|"p":>"im"<>x, StartOfString~~x:"r":>"ir"<>x, StartOfString~~x_:>"un"<>x } 

Finally this list is passed into StringReplace which gives an operator on strings.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Does Mathmatica have a builtin for everything? \$\endgroup\$ Commented Apr 5, 2017 at 21:14
2
\$\begingroup\$

Retina, 54 bytes

^[^hqlmpr] un$+ ^[hq] dis$+ ^l il$+ ^[mp] im$+ ^r ir$+ 

Explanation:

 {implicit replace stage} ^[^hqlmpr] Append un to words starting with none of: hqlmpr un$+ ^[hq] Append dis to words starting with h or q dis$+ ^l Append il to words starting with l il$+ ^[mp] Append il to words starting with m or p im$+ ^r Append ir to words starting with r ir$+ 

First time I've used Retina. It's a pretty neat language.

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Very nice first try at a language! +1 \$\endgroup\$ Commented Apr 6, 2017 at 8:22
  • \$\begingroup\$ And with that you have 2500 rep! Congratulations! \$\endgroup\$ Commented Apr 6, 2017 at 8:23
  • \$\begingroup\$ And your user index is 26600! \$\endgroup\$ Commented Apr 6, 2017 at 8:23
  • \$\begingroup\$ So much perfect base-10 ! \$\endgroup\$ Commented Apr 6, 2017 at 8:24
1
\$\begingroup\$

C, 109 107 bytes

f(char*s){printf("%s%s",*s-109&&*s-112?*s-108?*s-114?*s-104&&*s-113|s[1]-117?"un":"dis":"ir":"il":"im",s);} 

Try it online!

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

PHP, 101 Bytes

echo preg_match("#^(qu|[hlmpr])#",$argn,$t)?[qu=>dis,h=>dis,l=>il,m=>im,p=>im,r=>ir][$t[1]]:un,$argn; 

Online Version

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

Excel 78 bytes

=TRIM(MID(" disdisil im im ir un",IFERROR(FIND(LEFT(A1),"qhlmpr"),7)*3,3))&A1 

I found some close contenders using different methods that scored 81 bytes:

=IFERROR(CHOOSE(FIND(LEFT(A1),"qhlmpr"),"dis","dis","il","im","im","ir"),"un")&A1 

And 84 bytes:

=IFERROR(TRIM(MID("im disi"&LEFT(A1),MOD(FIND(LEFT(F1),"qlmhrp"),3)*3+1,3)),"un")&A1 
\$\endgroup\$
0
\$\begingroup\$

REXX, 78 bytes

arg a s.=un s.q=dis s.h=s.q s.l=il s.m=im s.p=im s.r=ir p=left(a,1) say s.p||a 

Saves a few bytes by replying in UPPERCASE, e.g. potent -> IMPOTENT.

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

Perl, 49 + 1 (-p flag) = 50 bytes

s|^[hq]|dis$&|||s|^[lmr]|i$&$&|||s|p|imp|||s||un| 

Using:

perl -pe 's|^[hq]|dis$&|||s|^[lmr]|i$&$&|||s|p|imp|||s||un|' <<< responsible 

Try it online.

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

Clojure, 65 bytes

#(str(get{\q"dis"\h"dis"\l"il"\m"im"\p"im"\r"ir"}(first %)"un")%) 

Well this is boring... but I couldn't make it any shorter. At least there is very little whitespace.

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

OCaml, 85

(fun s->(match s.[0]with|'q'|'h'->"dis"|'l'->"il"|'m'|'p'->"im"|'r'->"ir"|_->"un")^s) 

Anonymous function, uses pattern matching on its first char.

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

Vyxal, 38 bytes

«÷c4w«?hḟ:u=[`un`|4%«⟑Ẇf:«2ẇ`Ġ⟨`p$i]?+ 

Try it Online!

Messy.

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

PowerShell, 66 62 bytes

%4+1 inspired by @Steve Bennett

param($s)(echo un dis im il ir)[('qmlrhp'|% I*f $s[0])%4+1]+$s 

Try it online!

\$\endgroup\$