26
\$\begingroup\$

Challenge

Given a three digit octal permissions number, output the permissions that it grants.

chmod

On UNIX OSes file permissions are changed using the chmod command. There are few different ways of using chmod, but the one we will focus on today is using octal permissions.

The three digits in the permissions number represent a different person:

  • The first digit represents the permissions for the user
  • The second digit represents the permissions for the group
  • The last digit represents the permissions for others

Next, each digit represents a permission as shown below in:

Key: number | permission

7 | Read Write and Execute
6 | Read and Write
5 | Read and Execute
4 | Read only
3 | Write and Execute
2 | Write only
1 | Execute only
0 | None

Input

The input will be the three digit number as a string, e.g.:

133

or

007

This will be passed either via STDIN or via function arguments.

Output

Your output should be the different permissions for each of the user, the group and the others. You must display this information like so:

User:   ddd
Group:  ddd
Others: ddd

Where there are three spaces after User, two spaces after Group and one space after Others. You replace ddd with the permissions information.

Your output may be to STDOUT or as a returned string.

Examples

Input: 666

Output:

User:   Read and Write
Group:  Read and Write
Others: Read and Write

Input: 042

Output:

User:   None
Group:  Read only
Others: Write only

Input: 644

Output:

User:   Read and Write
Group:  Read only
Others: Read only

Winning

The shortest code in bytes wins.

\$\endgroup\$
  • \$\begingroup\$ What are the specifications of the input? \$\endgroup\$ – Jonathan Allan Sep 13 '16 at 11:23
  • \$\begingroup\$ @JonathanAllan Just the three digit number \$\endgroup\$ – Beta Decay Sep 13 '16 at 11:29
  • \$\begingroup\$ You mean as a decimal integer only, so 042 would be received as 42? \$\endgroup\$ – Jonathan Allan Sep 13 '16 at 11:31
  • 2
    \$\begingroup\$ @Jonathan No, it's a string input so it'd be 042 \$\endgroup\$ – Beta Decay Sep 13 '16 at 11:50
  • 1
    \$\begingroup\$ The output looks right with a tab character, so why not use it? Just to penal languages that need more bytes to pad a string? \$\endgroup\$ – Titus Sep 14 '16 at 11:32

32 Answers 32

3
\$\begingroup\$

05AB1E, 89 87 bytes

”‚Ý:‚Ù:ˆ†:”ð¡v”Šª0ÍÃ20‡í20‡í1ÍÃ0‚Ø20‚Ø1ÍÃ0‚Ø1‡í0‚؇í1ÍÔ2ð'€É«:1ð'€ƒ«:0ð«¡¹Nèèð3N-×ìyì,

Summons the Cthulhu encoding. Uses the CP-1252 encoding. Try it online!

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

Javascript (ES6), 165 161 bytes

n=>[0,1,2].map(i=>(s='User:  3Group: 68Others:58None576Read48Write476Execute475and4576only'.split(/(\d+)/))[i*2]+s[n[i]*2+1].replace(/./g,c=>' '+s[c*2])).join`
`

Edit: +1 byte to fulfill the "no tab" rule

Examples

let f =
n=>[0,1,2].map(i=>(s='User:  3Group: 68Others:58None576Read48Write476Execute475and4576only'.split(/(\d+)/))[i*2]+s[n[i]*2+1].replace(/./g,c=>' '+s[c*2])).join`
`
console.log(f("666"));
console.log(f("042"));
console.log(f("644"));
console.log(f("137"));

\$\endgroup\$
  • \$\begingroup\$ You can gain a few bytes by rearranging the array (and maybe separating the numbers from the strings). +1 for the idea. \$\endgroup\$ – Titus Sep 13 '16 at 15:45
  • \$\begingroup\$ @Titus - I've to admit that I fail to see a rearrangement that saves some bytes. Also, the numbers have to be treated as strings so that replace() works on them without coercing. But I may be missing your point. \$\endgroup\$ – Arnauld Sep 13 '16 at 15:59
  • \$\begingroup\$ @Titus - Something like 'User3Group68Others58None576Read48Write476Execute475and4576only'.split(/(\d+)/) might work. Is that what you had in mind? \$\endgroup\$ – Arnauld Sep 13 '16 at 16:22
  • \$\begingroup\$ I was misunderstanding them; thought they were octal values. :) But your new idea is not bad either. \$\endgroup\$ – Titus Sep 13 '16 at 16:26
  • \$\begingroup\$ Challenge output requires spaces instead of tabs as it is currently written. \$\endgroup\$ – Mwr247 Sep 14 '16 at 17:26
13
\$\begingroup\$

GNU sed, 187 163 158 (157+1) bytes

Run with -r (ERE regexp). File contains no trailing newline.

s/(.)(.)/User:   \1\nGroup:  \2\nOthers: /g
s/[4-7]/Read &/g
s/[2367]/Write &/g
s/[1357]/Execute &/g
s/(\w) (\w+) [1-7]/\1 and \2/g
s/[1-7]/only/g
s/0/None/g
\$\endgroup\$
  • \$\begingroup\$ Nice approach but you can save about 20 bytes by removing the digits when you add the and or only. \$\endgroup\$ – Neil Sep 13 '16 at 14:30
  • \$\begingroup\$ @Neil there :) incorporated your suggestion for a very significant save. \$\endgroup\$ – FireFly Sep 13 '16 at 14:48
  • 1
    \$\begingroup\$ The first line could be just: s/(.)(.)/User: \1\nGroup: \2\nOthers: /. Some more bytes could be saved by porting to Perl, which has \d and \K. \$\endgroup\$ – ninjalj Sep 16 '16 at 19:06
  • \$\begingroup\$ @ninjalj good point. I'll stick to sed since I don't know Perl, and I'm sure there'd be other tricks to pull there to make it even shorter, outside of s/// replacements. \$\endgroup\$ – FireFly Sep 18 '16 at 17:27
6
\$\begingroup\$

C# 214 Bytes

string h(string y){string e="Execute ",r="Read ",w="Write ",O="Only",a="and ";var z=new[]{"None",e+O,w+O,w+a+e,r+O,r+a+e,r+a+w,r+w+a+e};return$"User:   {z[y[0]-'0']}\nGroup:  {z[y[1]-'0']}\nOthers: {z[y[2]-'0']}";}
\$\endgroup\$
6
\$\begingroup\$

Jelly, 100 91 85 bytes

Almost certainly golfable - 91 bytes, what?! 8 months and 6 wisdom bytes!
- 1. more string compression;
- 2. remove the post-ordinal decrement by 48 since indexing is modular;
- 3. use better tacit chaining).

-9 bytes with the kind help of @Lynn running string compressions for me

,“£ɱ~»
Ñ
ṖK,“ and”,Ṫ
LĿK
7RBUT€Uị“ØJƓ“¥Ị£“¤/¡»Ç€“¡*g»ṭ
“ṖŒhJ"ỵd¡»ḲðJ4_⁶ẋ⁸,"j€”:ż⁹Oị¢¤Y

Test it at TryItOnline

How?

,“£ɱ~» - Link 1: pair with the string "Only"

Ñ - Link 2: call next link

ṖK,“ and”,Ṫ - Link 3: insert " and" between the last two elements of x
Ṗ           - x[:-1]
 K          - join with spaces
   “ and”   - the string " and"
          Ṫ - x[-1]
  ,      ,  - pair

LĿK - Link 4: call appropriate link and add missing spaces
L   - length
 Ŀ  - call link at that index
  K - join the result with spaces

7RBUT€Uị“ØJƓ“¥Ị£“¤/¡»Ç€“¡*g»ṭ - Link 5: construct all 8 cases
7R                            - range of 7: [1,2,3,4,5,6,7]
  B                           - binary (vectorises): [[1],[1,0],[1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
   U                          - reverse (vectorises): [[1],[0,1],[1,1],[0,0,1],[1,0,1],[0,1,1],[1,1,1]]
    T€                        - indexes of truthy values for each: [[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
      U                       - reverse (vectorises): [[1],[2],[2,1],[3],[3, 1],[3,2],[3,2,1]]
        “ØJƓ“¥Ị£“¤/¡»         - list of strings: ["Execute","Write","Read"]
       ị                      - item at index (vectorises): [["Execute"],["Write"],["Write","Execute"],["Read"],["Read","Execute",["Read","Write"],["Read","Write","Execute"]]
                     ǀ       - call the previous link for each
                       “¡*g»  - the string "None"
                            ṭ - tack (Jelly is 1-based so the 8th item will be indexed as 0)

“ṖŒhJ"ỵd¡»ḲðJṚ⁶ẋ⁸,"j€”:ż⁹Oị¢¤Y - Main Link: parse input and make the result. e.g.: "042"
“ṖŒhJ"ỵd¡»                     - dictionary compression of "User Group Others"
          Ḳ                    - split at spaces -> ["User","Group","Others"]
           ð                   - dyadic chain separation, call that g (input as right)
            J                  - range of length of g -> [1,2,3]
             Ṛ                 - reverse -> [3,2,1]
              ⁶                - literal space
               ẋ               - repeat -> ["   ","  "," "]
                ⁸              - chain's left argument, g
                  "            - zip with:
                 ,             -   pair -> [["User","   "],["Group","  "],["Others"," "]]
                     ”:        - literal ':'
                   j€          - join for €ach -> ["User:   ","Group:  ","Others: "]
                            ¤  - nilad followed by link(s) as a nilad:
                        ⁹      - chain's right argument, the input string -> "042"
                         O     -   cast to ordinal (vectorises) -> [48, 52, 50]
                           ¢   -   call last link (5) as a nilad  -> ["Execute Only","Write Only","Write and Execute","Read Only","Read and Execute","Read and Write","Read Write and Execute","None"]
                          ị    -   index into (1-based & modular) -> ["None","Read Only","Write Only"]
                       ż       - zip together -> [["User:   ","None"],["Group:  ","Read Only"],["Others: ","Write Only"]]
                             Y - join with line feeds -> ["User:   ","None",'\n',"Group:  ","Read Only",'\n',"Others: ","Write Only"]
                               - implicit print:
                                             >>>User:   None
                                             >>>Group:  Read Only
                                             >>>Others: Write Only
\$\endgroup\$
4
\$\begingroup\$

Octave, 185 bytes

@(n)fprintf('User:   %s\nGroup:  %s\nOthers: %s',{'Read Write and Execute','Read and Write','Read and Execute','Read only','Write and Execute','Write only','Execute only','None'}{56-n})

Create anonymous function that takes the input as a string: '042'. Convert it to an array: (56-'042)' = [0 4 2]. Use this as multiple cell indices to index the cell array with Read Write and Execute','Read and Write', .... Uses fprintf to output the three strings, with the appropriate categories: User:, Group: and Others:.

I tried finding a way to store Execute, Write, Read as separate words and concatenate as needed, but this turned out longer than the naive approach.

Examples:

1> f('000')
User:   None
Group:  None
Others: None
2> f('042')
User:   None
Group:  Read only
Others: Write only

Try it online.

\$\endgroup\$
  • 2
    \$\begingroup\$ You can save a few bytes using strsplit('Read Write and Execute*Read and Write*Read and Execute*Read only*Write and Execute*Write only*Execute only*None','*') instead of the cell array literal \$\endgroup\$ – Luis Mendo Sep 13 '16 at 15:35
4
\$\begingroup\$

PowerShell v2+, 189 168 bytes

[char[]]$args[0]|%{('User','Group','Others')[$i++]+":`t"+('None','Read','Write','Execute','only','and')[(0,(3,4),(2,4),(2,5,3),(1,4),(1,5,3),(1,5,2),(1,2,5,3))[$_-48]]}

Loops through the input $args[0] as a char-array. Each iteration, we index into an array with $i++ (defaults to 0) to select User, Group, or Others, concatenate that with a colon and a tab, and concatenate that with another array index.

Here's the magic. We implicitly cast the char to an int and subtract 48 (i.e., turning ASCII 48 ("0") into 0), choosing the appropriate wording as an array of ints. That array is subsequently used as the index into the 'None','Read','Write','Execute','only','and' array. Since the default $ofs (Output Field Separator) is a space, this correctly inserts spaces between the array elements when stringified (which happens when it concatenates to the left).

These three strings are left on the pipeline, and output via implicit Write-Output happens at program completion.

Example

PS C:\Tools\Scripts\golfing> .\decode-the-chmod.ps1 '123'
User:   Execute only
Group:  Write only
Others: Write and Execute
\$\endgroup\$
3
\$\begingroup\$

Straw, 193 bytes

((01234567)((None)(Execute only)(Write only)(Write and Execute)(Read only)(Read and Execute)(Read and Write)(Read Write and Execute)))::~<:{-¢(User:   ),+>
>}:{-¢(Group:  ),+>
>}-¢(Others: ),+>

Try it online

Push 3 times a conversion table on the first stack, switch to the second stack, convert each number using the conversation table and print.

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

Haskell, 186 Bytes

s=zip(words"7654 6 7632 753 7531 0 421")(words"Read and Write and Execute None only")
m c=mapM_(\(x,y)->putStrLn(x++unwords[b|(a,b)<-s,elem y a]))$zip["User:   ","Group:  ","Others: "]c

Example:

Prelude> :r
[1 of 1] Compiling Main             ( decCh.hs, interpreted )
Ok, modules loaded: Main.
*Main> m "654"
User:   Read and Write
Group:  Read and Execute
Others: Read only

Only Prelude used. Am I doing this right?

Ungolfed:

s = zip (words "7654 6 7632 753 7531 0 421")
        (words "Read and Write and Execute None only")

ps y = unwords [b|(a,b)<-s,elem y a] -- build permissions string
pp (x,y) = putStrLn $ x ++ ps y -- print user + permission

m c =   let up = zip ["User:   ","Group:  ","Others: "] c -- pair user and permission
        in mapM_ pp up --print each
\$\endgroup\$
2
\$\begingroup\$

Python 2, 190 185 bytes

def f(i):
 r,w,a,x,o,g="Read ","Write ","and ","Execute ","only",["User:  ","Group: ","Others:"];p=["None",x+o,w+o,w+a+x,r+o,r+a+x,r+a+w,r+w+a+x]
 for z in 0,1,2:print g[z],p[int(i[z])]

Leaves a trailing space if Execute or Write are at the end of the line but I didn't see that this wasn't allowed.

EDIT Saved 5 bytes by changing range(3) to 0,1,2 and checking byte count on my Linux laptop instead of my Windows one (\n = \r\n or the other way round. I can never remember which).

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

Python 2, 240 239 238 237 228 bytes

I thought I’d finally give this cold golf thing a go. Hopefully trailing whitespace is allowed. (fixed, and in the process saved a byte)

i=0
def a(b):
 for d in 4,2,1:
    if b&d:yield('Execute','Write','Read')[d/2]
for k in raw_input():
 b,q=list(a(int(k))),' and';e=len(b)
 if e:b[~e/2]+=(' only',q,q)[e-1]
 print'UGOsrteohrue:pr :s  :'[i::3],' '.join(b)or None;i+=1
\$\endgroup\$
  • \$\begingroup\$ Welcome to PPCG, and nice first answer! \$\endgroup\$ – ETHproductions Sep 14 '16 at 16:17
  • \$\begingroup\$ I have shamelessly replaced the range(3) in my Python 2 answer to 0,1,2 after reading through your code. Nice answer. +1 \$\endgroup\$ – ElPedro Sep 14 '16 at 21:08
2
\$\begingroup\$

PHP, 169 159 bytes

foreach([User,Group,Others]as$i=>$u){echo"
$u: ";for($n=[5,33,34,66,35,67,131,531][$i]];$n;$n>>=3)echo["and",Execute,Write,Read,only,None][$n&7]," ";}

takes string as command line argument: php -r '<code>' <argument>,
prints a leading newline instead of a trailing one

Thanks to Jörg for pointing out my bugs - and for the \t.

PHP, 169 bytes

with the new restriction: (tab character forbidden)

foreach(['User:  ','Group: ','Others:']as$i=>$u){echo"
$u";for($n=[5,33,34,66,35,67,131,531][$argv[1][$i]];$n;$n>>=3)echo' ',['and',Read,Write,Execute,only,None][$n&7];}

This is 1 byte shorter than with str_pad, because of the additional blank it would require.

breakdown

foreach([User,Group,Others]as$i=>$u)
{
    echo"\n$u:\t";                      // print newline, who, blanks
    for($n=[5,33,34,66,35,67,131,531]   // octal values for words indexes
        [$argv[1][$i]]                  // (last word=highest digit)
        ;$n;$n>>=3)                     // while value has bits left
        echo['and',Execute,Write,Read,only,None][$n&7]," "; // print that word
}

To create the array for $n, use this:

$b=[[5],[1,4],[2,4],[2,0,1],[3,4],[3,0,1],[3,0,2],[3,2,0,1]];
foreach($b as$i=>$a){for($v=$j=0;$a;$j+=3)$v+=array_shift($a)<<$j;echo"$v,";}
\$\endgroup\$
  • 1
    \$\begingroup\$ foreach(['User','Group','Others']as$i=>$u){echo"\\n$u:\\t"; saves some bytes and the output for 3,4,6 is wrong \$\endgroup\$ – Jörg Hülsermann Sep 13 '16 at 16:17
  • 1
    \$\begingroup\$ This is the right order [5,33,34,66,35,67,131,531] nice idea \$\endgroup\$ – Jörg Hülsermann Sep 13 '16 at 16:29
  • \$\begingroup\$ I have forget 'User' to User for exmple saves the next 6 Bytes you want to beat JavaScript do it \$\endgroup\$ – Jörg Hülsermann Sep 13 '16 at 16:38
  • \$\begingroup\$ @JörgHülsermann: I was about to adopt the "\t" anyway; thanks. +1 for that :) Good eye on the 33! \$\endgroup\$ – Titus Sep 13 '16 at 16:50
  • 1
    \$\begingroup\$ for 346 our output is User: Read and Write Group: Execute only Others: Write and Execute it should User: Write and Execute Group: Read Only Others: Read and Write \$\endgroup\$ – Jörg Hülsermann Sep 13 '16 at 17:11
2
\$\begingroup\$

bash - 221 213 bytes

GNU bash, version 4.3.46

l=("User:   " "Group:  " "Others: ")
o=\ only;a=" and ";x=Execute;w=Write;r=Read
b=(None "$x$o" "$w$o" "$w$a$x" "$r$o" "$r$a$x" "$r$a$w" "$r $w$a$x")
for c in `echo $1|grep -o .`;{ echo "${l[$((z++))]}${b[$c]}";}

Unclear if this can be condensed any further, at least not without fundamentally changing the approach here (splitting up input and using it as an index to the array ${b} that holds the corresponding strings).

\$\endgroup\$
  • 1
    \$\begingroup\$ It's shorter with \ only expanded inline. grep -o .<<<$1 is shorter than echo $1|grep -o ., but reading the input from stdin with while read -n1 c is better. Array indexes have arithmethic context in bash, so ${l[z++]} works. l would be shorter as a string, which would be accessed as ${l:z++*8:8} (offset and length have arithmethic context). Another byte can be sh?aved by reading the whole mode in c, expanding "User: ", ... inline and making judicious use of parameter expansions. \$\endgroup\$ – ninjalj Sep 20 '16 at 23:13
  • 1
    \$\begingroup\$ For an end result of: a=" and ";x=Execute;w=Write;r=Read;b=(None $x\ only $w\ only "$w$a$x" $r\ only "$r$a$x" "$r$a$w" "$r $w$a$x");read c;echo "User: ${b[${c%??}]}\nGroup: ${b[${c:1:1}]}\nOthers: ${b[${c:2}]}" (replace \n with literal newlines). \$\endgroup\$ – ninjalj Sep 20 '16 at 23:14
1
\$\begingroup\$

Java 7, 300 284 bytes

String c(String s){char[]a=s.toCharArray();return"User:   "+f(a[0])+"Group:  "+f(a[1])+"Others: "+f(a[2]);}String f(int i){return new String[]{"None","Execute only","Write only","Write and Execute","Read only","Read and Execute","Read and Write","Read Write and Execute"}[i%48]+"\n";}

Direct approach for now. Will try to come up with a more generic approach to reuse the words.

Ungolfed & test cases:

Try it here.

class M{
  static String c(String s){
    char[] a = s.toCharArray();
    return "User:   " + f(a[0]) + "Group:  " + f(a[1]) + "Others: " + f(a[2]);
  }

  static String f(int i){
    return new String[]{ "None", "Execute only", "Write only", "Write and Execute", "Read only", "Read and Execute", "Read and Write", "Read Write and Execute" }
      [i % 48] + "\n";
  }

  public static void main(String[] a){
    System.out.println(c("666"));
    System.out.println(c("042"));
    System.out.println(c("644"));
  }
}

Output:

User:   Read and Write
Group:  Read and Write
Others: Read and Write

User:   None
Group:  Read only
Others: Write only

User:   Read and Write
Group:  Read only
Others: Read only
\$\endgroup\$
1
\$\begingroup\$

Groovy, 217 207 205 bytes

def c(m){def i=0,e='Execute',w='Write',r='Read',o=' only',a=' and ';m.each{println(['User:   ','Group:  ','Others: '][i++]+['None',"$e$o","$w$o","$w$a$e","$r$o","$r$a$e","$r$a$w","$r $w$a$e"][it as int])}}

ungolfed:

def c(m) {
  def i=0,e='Execute',w='Write',r='Read',o=' only',a=' and ';
  m.each{
    println(['User:   ','Group:  ','Others: '][i++]+['None',"$e$o","$w$o","$w$a$e","$r$o","$r$a$e","$r$a$w","$r $w$a$e"][it as int])
  }
}
\$\endgroup\$
1
\$\begingroup\$

Mathematica, 211 bytes

{r,w,e,o,a}={"Read ","Write ","Execute ","only ","and "};""<>Transpose@{{"User:   ","Group:  ","Others: "},"None"[{e,o},{w,o},{w,a,e},{r,o},{r,a,e},{r,a,w},{r,w,a,e}][[#]]&/@IntegerDigits[#,10,3],"\n"&~Array~3}&

A straightforward implementation (probably easily beatable): doesn't compute anything, just hard-codes each possible output. Input is an integer; outputs each line with a trailing space, and a trailing newline overall.

IntegerDigits[#,10,3] gives the three digits of the input (even if there are leading zeros). Each digit indicates an argument of the "function"

"None"[{e,o},{w,o},{w,a,e},{r,o},{r,a,e},{r,a,w},{r,w,a,e}]

with 0 indicating the function name itself. ""<> concatenates all the strings in a list (of lists). "\n"&~Array~3 produces the three newlines.

\$\endgroup\$
  • \$\begingroup\$ I just noticed that my Python 2 answer is almost identical to yours, even using the same variable names. I honestly hadn't seen yours before I posted! \$\endgroup\$ – ElPedro Sep 14 '16 at 12:03
  • 1
    \$\begingroup\$ no worries! I think the variable names' matching is pretty much to be expected in this situation :) \$\endgroup\$ – Greg Martin Sep 14 '16 at 17:59
  • \$\begingroup\$ Guess you're right. The variable names were a bit predictable ☺ \$\endgroup\$ – ElPedro Sep 14 '16 at 18:21
  • \$\begingroup\$ btw, +1 cos we think the same way :-) \$\endgroup\$ – ElPedro Sep 14 '16 at 20:06
  • 1
    \$\begingroup\$ btw, I don't know Mathematica but I think you may be able to lose a byte by removing the space from "only ". It will always be at the end of a line so doesn't need a trailing space. \$\endgroup\$ – ElPedro Sep 14 '16 at 20:10
1
\$\begingroup\$

Java 7, 278

Golfed:

String f(String i){String o="";for(int n=0;n<i.length();)o+=(n<1?"User:   ":n<2?"Group:  ":"Others: ")+new String[]{"None","Execute only","Write only","Write and Execute","Read only","Read and Execute","Read and Write","Read Write and Execute"}[i.charAt(n++)-48]+"\n";return o;}

Ungolfed:

  String f(String i) {
    String o = "";
    for (int n = 0; n < i.length();)
      o += (n < 1 ? "User:   " : n < 2 ? "Group:  " : "Others: ")
        + new String[] { "None", "Execute only", "Write only", "Write and Execute", "Read only", "Read and Execute",
            "Read and Write", "Read Write and Execute" }[i.charAt(n++) - 48]
        + "\n";
    return o;
  }

Output:

User:   Read and Write
Group:  Read and Write
Others: Read and Write

User:   None
Group:  Read only
Others: Write only

User:   Read and Write
Group:  Read only
Others: Read only
\$\endgroup\$
1
\$\begingroup\$

Python 3.5, 3.6 - 235 232 228 216 bytes

(should work on all Python 3.x)

So the input is on STDIN here (saves an import ☺).

a=input()
r=range
for i in r(3):
 p=int(a[i]);x=[["Read","Write","Execute"][j]for j in r(3)if 4>>j&p]
 if x[1:]:x[-1:-1]="and",
 if len(x)==1:x+="only",
 print(["User:  ","Group: ","Others:"][i]," ".join(x)or"None")

Making use of tuples, omitting spaces where possible and operator precedence where you would normally put parentheses to make your intentions clear.

Sample usage:

$ echo -n '666' | python3 golf2.py
User:   Read and Write
Group:  Read and Write
Others: Read and Write
$ echo -n '644' | python3 golf2.py
User:   Read and Write
Group:  Read only
Others: Read only
$ echo '042' | python3 golf2.py
User:   None
Group:  Read only
Others: Write only
$ echo '123' | python3 golf2.py
User:   Execute only
Group:  Write only
Others: Write and Execute
$ echo -n '777' | python3 golf2.py
User:   Read Write and Execute
Group:  Read Write and Execute
Others: Read Write and Execute

Un-golfed:

input_perms = list(map(int, input()))

entities = ["User", "Group", "Others"]
perm_names = ["Read", "Write", "Execute"]

for i in range(3):
    bits = input_perms[i]
    perms = [
        perm_names[j]
        for j in range(3)
        if (1 << (2-j)) & bits
    ]

    if len(perms) > 1:
        perms.insert(-1, "and")
    if len(perms) == 1:
        perms.append("only")

    print("{:7} {}".format(
        entities[i]+":",
        " ".join(perms) or "None"
    ))
\$\endgroup\$
1
\$\begingroup\$

Batch, 280 bytes

@echo off
set/pc=
call:l "User:   " %c:~0,1%
call:l "Group:  " %c:~1,1%
call:l "Others: " %c:~2,1%
exit/b
:l
for %%s in (None.0 Execute.1 Write.2 "Write and Execute.3" Read.4 "Read and Execute.5" "Read and Write.6" "Read Write and Execute.7") do if %%~xs==.%2 echo %~1%%~ns

Hardcoding the strings was 47 bytes shorter than trying to piece them together. Would have been 267 bytes if tabs were legal.

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

C# 307 241 210 bytes

string X(string s){var z="User: ,Group: ,Others:,5,34,14,123,04,023,021,0123,Read,Write,and,Execute,only,None".Split(',');return string.Join("\n",s.Zip(z,(a,b)=>b+z[a-45].Aggregate("",(x,y)=>x+" "+z[y-37])));}

Formatted

string X(string s)
{
    var z = "User:  ,Group: ,Others:,5,34,14,123,04,023,021,0123,Read,Write,and,Execute,only,None".Split(',');
    return string.Join("\n", s.Zip(z, (a, b) => b + z[a - 45].Aggregate("", (x, y) => x + " " + z[y - 37])));
}
\$\endgroup\$
1
\$\begingroup\$

C#, 322 337 348 bytes

That's for sure not the shortest version, but I tried solving this problem using bitwise operators since the chmod values are actually bit flags. Also C# is probably not the best golfing language :D

string P(string s){Func<int,string>X=p=>{var a=new List<string>();if((p&4)>0)a.Add("Read");if((p&2)>0)a.Add("Write");if((p&1)>0)a.Add("Execute");return a.Count>1?string.Join(" ",a.Take(a.Count-1))+" and "+a.Last():a.Count>0?a.First()+" only":"none";};return string.Join("\n",(new[]{"User:   ","Group:  ","Others: "}).Select((c,i)=>c+X(s[i]-'0')));}

ungolfed: (with comments)

string P(string s)
{
    // Function that determines the permissions represented by a single digit (e.g. 4 => "Read only")
    Func<int, string> X = p => 
    {
        var a = new List<string>();         // temporary storage for set permissions
        if ((p & 4) > 0) a.Add("Read");     // Read bit set
        if ((p & 2) > 0) a.Add("Write");    // Write bit set
        if ((p & 1) > 0) a.Add("Execute");  // Execute bit set

        // actually just Output formatting ... Takes a lot of bytes *grr*
        return a.Count > 1 
            ? string.Join(" ", a.Take(a.Count - 1)) + " and " + a.Last() 
            : a.Count > 0 
                ? a.First() + " only" 
                : "none";
    };

    // Actual result:
    return string.Join("\n", (new[] { "User:   ", "Group:  ", "Others: " })
        .Select((c, i) => c + X(s[i] - '0'))); // Map "User, .." to its permissions by using above function
}

This is my first time code golfing, so please tell me, if I did anyting wrong :)

EDIT 1:

Saved some bytes by replacing s[i]-'0' by s[i]&7 (at the very end) and saving list count into variable:

string P(string s){Func<int,string>X=p=>{var a=new List<string>();if((p&4)>0)a.Add("Read");if((p&2)>0)a.Add("Write");if((p&1)>0)a.Add("Execute");var c=a.Count;return c>1?string.Join(" ",a.Take(c-1))+" and "+a.Last():c>0?a[0]+" only":"none";};return string.Join("\n",(new[]{"User:   ","Group:  ","Others: "}).Select((c,i)=>c+X(s[i]&7)));}

EDIT 2:

Changed to lambda expression:

s=>{Func<int,string>X=p=>{var a=new List<string>();if((p&4)>0)a.Add("Read");if((p&2)>0)a.Add("Write");if((p&1)>0)a.Add("Execute");var c=a.Count;return c>1?string.Join(" ",a.Take(c-1))+" and "+a.Last():c>0?a[0]+" only":"none";};return string.Join("\n",(new[]{"User:   ","Group:  ","Others: "}).Select((c,i)=>c+X(s[i]&7)));}
\$\endgroup\$
1
\$\begingroup\$

Javascript, 213 209 208 188 186 bytes

function(d){a=" and ";r="Read";w="Write";e="Execute";v=";";o=" only";c=["None",e+o,w+o,w+a+e,r+o,r+a+e,r+a+w,r+" "+w+a+e];return"User: "+c[d[0]]+"\nGroup: "+c[d[1]]+"\nOthers: "+c[d[2]]}

Saved 20 bytes thanks to Dada!

\$\endgroup\$
  • 3
    \$\begingroup\$ I might be mistaken, but shouldn't your array be in the opposite order? If I call b("000"), it returns "Read Write and Execute" while one could expect "None"... \$\endgroup\$ – Dada Sep 13 '16 at 12:52
  • \$\begingroup\$ And I'm pretty sure this could be more golfed. For instance, a 191 byte version : function b(p){a=" and ";r="Read";w="Write";e="Execute";v=";";o=" only";c=["None",e+o,w+o,w+a+e,r+o,r+a+e,r+a+w,r+" "+w+a+e];return"User: "+c[p[0]]+"\nGroup: "+c[p[1]]+"\nOthers: "+c[p[2]]}. \$\endgroup\$ – Dada Sep 13 '16 at 13:02
1
\$\begingroup\$

Visual Basic, 606 Bytes

imports System.Collections
module h
sub main()
Dim i As String=console.readline()
Dim s=new Stack(new String(){"Others: ","Group:  ","User:   "})
for each j as Char in i
dim t=new Stack()
if((asc(j) MOD 2)=1)then t.push("Execute")
if(asc(j)=50 or asc(j)=51 or asc(j)=54 or asc(j)=55)then t.push("Write")
if(asc(J)>51)then t.push("Read")
if t.count=3 then
w(s.pop+t.pop+" "+t.pop+" and "+t.pop)
else
if t.count=2 then
w(s.pop+t.pop+" and "+t.pop)
else
if t.count=0 then
w(s.pop+"None")
else
w(s.pop+t.pop+" only")
end if
end if
end if
next
end sub
sub w(s As String)
console.writeline(s)
end sub
end module
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG! Nice first answer BTW :) \$\endgroup\$ – Beta Decay Jun 3 '17 at 10:11
1
\$\begingroup\$

Crystal, 200 194 Bytes

def m(y)y=y.chars.map &.to_i
a=" and "
o=" only"
r="Read"
w="Write"
x="Execute"
c=["None",x+o,w+o,w+a+x,r+o,r+a+x,r+a+w,r+" "+w+a+x]
"User:   "+c[y[0]]+"
Group:  "+c[y[1]]+"
Others: "+c[y[2]]end

returns the resulting string for a given octal-sequence as a string. e.g.: m("670") results to: User: Read and Write\nGroup: Read Write and Execute\nOthers: None.

Try it online.

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

C#, 371 bytes

public String[] a = {"none","Execute only","Write only","Write and Execute","Read only","Read and Execute","Read and Write","Read Write and Execute"};
public String pA(int i){return a[i];}
public int d(int n,int i){
  n=n/Math.pow(10,i);
  return n%=10;
}
public void main(int i){
  Console.Write("User:\t{0}\nGroup:\t{1},Others:\t{2}",pA(d(i,0)),pA(d(i,1)),pA(d(i,2));
}
\$\endgroup\$
  • 4
    \$\begingroup\$ This is code-golf, so you must golf your code. Also, add a header with the name of the language and the bytecount. \$\endgroup\$ – TuxCrafting Sep 13 '16 at 12:07
  • \$\begingroup\$ I've added your byte count, which is your score. You need to get your score as low as possible to win \$\endgroup\$ – Beta Decay Sep 13 '16 at 12:10
  • \$\begingroup\$ For example, you get rid of all of the unnecessary whitespace in each function \$\endgroup\$ – Beta Decay Sep 13 '16 at 12:10
  • 1
    \$\begingroup\$ @BetaDecay Thanks,I'm new to this community and I think I'd better to use php instead which could be lead to more compacts codes. \$\endgroup\$ – Alireza Tabatabaeian Sep 13 '16 at 12:13
  • 1
    \$\begingroup\$ @Alireza That's a good idea. Although on this site, we do like to see short answers in Java and C# :) \$\endgroup\$ – Beta Decay Sep 13 '16 at 12:17
0
\$\begingroup\$

Python 3.5 - 370 294 243 bytes

Golfed:

import sys
a=lambda o: [print(('User:  ','Group: ','Others:')[n],('None','Execute only','Write only','Write and Execute','Read only','Read and Execute','Read and Write','Read Write and Execute')[int(o[n])]) for n in range(0,3)]
a(sys.argv[1])

Size check:

$ du -b OctalToHuman.py 
243     OctalToHuman.py

Un-golfed:

#!/usr/bin/env python3
from sys import argv as ARGS

types = ('User:  ', 'Group: ', 'Others:')
perms = ('None','Execute only','Write only','Write and Execute','Read only','Read and Execute','Read and Write','Read Write and Execute')

def convert(octal_string):
    for n in range(0,3):
        print(types[n], perms[int(octal_string[n])])

if __name__ == '__main__':
    convert(ARGS[1])

Sample output:

$ python ./OctalToHuman.py 666
User:   Read and Write
Group:  Read and Write
Others: Read and Write

$ python ./OctalToHuman.py 042
User:   None
Group:  Read only
Others: Write only

$ python ./OctalToHuman.py 644
User:   Read and Write
Group:  Read only
Others: Read only
\$\endgroup\$
  • \$\begingroup\$ This is not a serious contender for the winning criteria. We require all answers to make a serious attempt at optimizing their score for the winning criteria (for example, in code golf challenges such as this one, submissions must make a serious attempt at minimizing the byte count of the program). \$\endgroup\$ – Mego Sep 13 '16 at 19:06
  • \$\begingroup\$ You can save quite a few bytes by removing import sys, and just making the program an anonymous function (lambda o:...). \$\endgroup\$ – NoOneIsHere Sep 18 '16 at 17:31
0
\$\begingroup\$

F#, 204 203 Bytes

my first golf, so do please forgive any mistakes ;)
The golfed version (based 1:1 on pinkfloydx33's answer):

fun(y:string)->let e,r,w,o,a="Execute ","Read ","Write ","only","and ";let z=["None";e+o;w+o;w+a+e;r+o;r+a+e;r+a+w;r+w+a+e;];let(!-)a=z.[int y.[a]-48];sprintf"User:   %s\nGroup:  %s\nOthers: %s"!-0!-1!-2

The ungolfed version:

fun (y : string) ->
    let e, r, w, o, a = "Execute ", "Read ", "Write ", "only", "and "
    let z = [
                "None";
                e + o;
                w + o;
                w + a + e;
                r + o;
                r + a + e;
                r + a + w;
                r + w + a + e;
            ]
    let (!-) a = z.[int(y.[a]) - 48]
    sprintf "User:   %s\nGroup:  %s\nOthers: %s" !-0 !-1 !-2

Example usage:

let k =  ...... // function definition goes here

printf"%s"<|k"755"
printf"%s"<|k"042"
// etc ...


This is solely to check, whether I could 'improve' pinkfloydx33's answer - I do not take any credit for the algorithm

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

PHP ,199 Bytes

foreach([User,Group,Others]as$i=>$u){$a=[];foreach([Read,Write,Execute]as$k=>$s)if($argv[1][$i]&4>>$k)$a[]=$s;$a[]=($x=array_pop($a))?$a?"and $x":"$x only":None;echo str_pad("\n$u:",9).join(" ",$a);}

PHP ,189 Bytes with \t

foreach([User,Group,Others]as$i=>$u){$a=[];foreach([Read,Write,Execute]as$k=>$s)if($argv[1][$i]&4>>$k)$a[]=$s;$a[]=($x=array_pop($a))?$a?"and $x":"$x only":None;echo"\n$u:\t".join(" ",$a);}
\$\endgroup\$
  • \$\begingroup\$ Hey, you should use spaces instead of tabs \$\endgroup\$ – Beta Decay Sep 14 '16 at 10:11
  • \$\begingroup\$ In this case \t looks like str_repeat(" ",3-$i) or str_pad("",3-$i," ") but is does not matter with my idea I have no chance to win.If I Should take another space cs.tut.fi/~jkorpela/chars/spaces.html \$\endgroup\$ – Jörg Hülsermann Sep 14 '16 at 11:12
  • 1
    \$\begingroup\$ 13+34 bytes to save. In the long version: Use echo str_pad("$u:",8) instead of echo"$u:".str_repeat(" ",3-$i) (-9); this renders $i=> obsolete (-4). In both versions: Use $a[$z-1]="and $a[$z-1]"; instead of {$a[]=$a[$z-1];$a[$z-1]="and";} (-7) and else$a[]=$a?Only:None; instead of elseif($z<1)$a[]=None;else$a[]=Only; (-14). Turn if(1<$z=count($a))$a[$z-1]="and $a[$z-1]";else$a[]=$a?Only:None; into if($x=array_pop($a))$a[]=$a?"and $x":"$x Only";else$a[]=None; (-3) and then into $a[]=($x=array_pop($a))?$a?"and $x":"$x Only":None; (-10) \$\endgroup\$ – Titus Sep 14 '16 at 12:29
  • \$\begingroup\$ @Titus echo str_pad("$u:",8),$a[$z-1]="and $a[$z-1]";,else$a[]=$a?Only:None; Done $i=> obsolete I can not do then $m=$argv[1][$i] is necessary. For the rest I would try first another way. Thank You for the input \$\endgroup\$ – Jörg Hülsermann Sep 14 '16 at 14:52
  • 1
    \$\begingroup\$ More ideas: if(4&$m=$argv[1][$i]) instead of $m=$argv[1][$i];if(4&$m) (-3) OR replace $m=;if();if();if(); with a loop: foreach([Read,Write,Execute]as$k=>$s)if($argv[1][$i]&4>>$k)$a[]=$s; (-7) \$\endgroup\$ – Titus Sep 14 '16 at 15:16
0
\$\begingroup\$

Python 3, 191 bytes

def d(n):a,b,c,d,e=' and ',' only',"Execute","Write","Read";l=["None",c+b,d+b,d+a+c,e+b,e+a+c,e+a+d,e+" "+d+a+c];y,u,i=map(int,n);return"User:   %s\nGroup:  %s\nOthers: %s\n"%(l[y],l[u],l[i])

ungolfed

def d(n):
    a,b,c,d,e=' and ',' only',"Execute","Write","Read"
    l=["None",c+b,d+b,d+a+c,e+b,e+a+c,e+a+d,e+" "+d+a+c]
    y,u,i=map(int,n)
    return"User:   %s\nGroup:  %s\nOthers: %s\n"%(l[y],l[u],l[i])
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG! nice first post! \$\endgroup\$ – Rɪᴋᴇʀ Sep 15 '16 at 1:34
  • \$\begingroup\$ Hmm, I'm very curious how moderator got 151bytes when I only get 191 :D Is it mistake? Check edits \$\endgroup\$ – Aleksandr Smirnov Sep 15 '16 at 9:11
  • \$\begingroup\$ That was me, sorry. I typo'ed in the edit. Fixed now. \$\endgroup\$ – Rɪᴋᴇʀ Sep 15 '16 at 14:13
0
\$\begingroup\$

Javascript (ES6), 159 bytes

a=>`User:  ${(b=[' None',(c=' Execute')+(d=' only'),(e=' Write')+d,f=e+(g=' and')+c,(h=' Read')+d,h+g+c,h+g+e,h+f])[a[0]]}\nGroup: ${b[a[1]]}\nOthers:`+b[a[2]]

Example:

(a=>`User:  ${(b=[' None',(c=' Execute')+(d=' only'),(e=' Write')+d,f=e+(g=' and')+c,(h=' Read')+d,h+g+c,h+g+e,h+f])[a[0]]}\nGroup: ${b[a[1]]}\nOthers:`+b[a[2]])("042")
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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