5
\$\begingroup\$

In the IRC protocol, raw messages look similar to this:

command arg1 arg2 :arg3 with spaces :arg4 with spaces :arg5

In a shell environment (e.g. bash), that would be equivalent to:

command arg1 arg2 "arg3 with spaces" "arg4 with spaces" arg5

The format specification is as follows:

  • Raw messages will only contain printable ASCII characters (ordinals 32-126).
  • Raw messages will start with a command, which will not contain any spaces.
  • Any number of arguments may follow a command. Arguments are delimited by one or more spaces followed by a colon (<space>: and <space><space>: are both valid delimiters).
    • Any arguments that do not contain spaces may omit the colon from the delimiter so long as all previous arguments (if any) have omitted the colon.
  • Colons will not appear within arguments or commands.
  • Arguments will not begin with a space.

For example, these are all valid raw messages:

join #foo #bar #baz
msg person hi
msg #channel :hello world
help :how do I use IRC
foo bar :baz bip :abc def :ghi

These are all invalid raw messages:

error :n:o colons within arguments
error ::need spaces between colons
:error no colons in commands
error non-ASCII character Ω

Given a valid raw IRC message as input, output a list containing the command and the arguments, properly parsed.

Test Cases

"join #foo #bar #baz" -> ["join", "#foo", "#bar", "#baz"]
"msg person hi" -> ["msg", "person", "hi"]
"msg #channel :hello world" -> ["msg", "#channel", "hello world"]
"help :how do I use IRC" -> ["help", "how do I use IRC"]
foo bar :baz bip :abc def :ghi :xyz -> ["foo", "bar", "baz bip", "abc def", "ghi", "xyz"]
\$\endgroup\$
  • \$\begingroup\$ Could the final argument end with spaces? \$\endgroup\$ – Jonathan Allan Dec 3 '16 at 0:16
  • \$\begingroup\$ @JonathanAllan Yes \$\endgroup\$ – Mego Dec 3 '16 at 1:43
  • \$\begingroup\$ Can we assume that input will be valid? \$\endgroup\$ – Titus Dec 4 '16 at 12:48
  • \$\begingroup\$ @Titus Yes, that was the goal of defining what constitutes valid input. \$\endgroup\$ – Mego Dec 4 '16 at 23:32
  • \$\begingroup\$ Does the output have to be a flat list? \$\endgroup\$ – Brad Gilbert b2gills Dec 8 '16 at 16:36
1
\$\begingroup\$

Jelly, 19 bytes

;⁷œṣ⁾ :µḢḲ;œr€⁶ỴF$€

A monadic link that returns a list.

Note: As a full program the implicit print that Jelly performs may be a little confusing in this case, since a list containing strings (really lists of characters in Jelly) is printed as if it were a single string. So, for completeness here are test harnesses employing the quick Ç which calls the previous link monadically:

  1. shows the Jelly representation of a list of character lists;
  2. Y joins the list with line feeds;
  3. ŒṘ shows the underlying Python representation (showing the actual lists of characters).

How?

Handling the edge case of possible trailing spaces for the ultimate argument (the only one which may have trailing spaces) is quite an expense at 6 bytes; maybe there is a shorter way?

;⁷œṣ⁾ :µḢḲ;œr€⁶ỴF$€ - Link expecting a single list of characters as input
;                   - concatenate
 ⁷                  - a line feed (to avoid right trimming spaces from ultimate argument)
  œṣ                - split on sublists equal to
    ⁾ :             -     two character list [' ',':']
       µ            - monadic chain separation (call the split result z)
        Ḣ           - head - pop first element (modifies z)
         Ḳ          - split at spaces
          ;         - concatenate with z
              ⁶     - space
           œr€      - right-strip from €ach
                 $€ - last two links as a monad for €ach
               Ỵ    -     split on line feeds
                F   -     flatten (removes the line feed from the beginning)
\$\endgroup\$
  • \$\begingroup\$ How does this handle <space><space>:? \$\endgroup\$ – isaacg Dec 2 '16 at 23:52
  • \$\begingroup\$ @isaacg - thanks for pointing that out, I have fixed it up, although it opened up an edge case I had to address too. \$\endgroup\$ – Jonathan Allan Dec 3 '16 at 11:48
  • \$\begingroup\$ I think you can add the Ṙ×0 test harness too. \$\endgroup\$ – Erik the Outgolfer Dec 4 '16 at 13:54
2
\$\begingroup\$

PHP, 87 bytes

$a=($s=preg_split)("# +:#",$argv[1]);array_splice($a,0,1,$s("# +#",$a[0]));print_r($a);

The first regex splits the argument by one or more spaces followed by a colon.
The second regex splits the first element by one or more spaces with no colon.
array_splice replaces the first element with the result of the second preg_split.
print_r prints the resulting array.

function version for testing

$cases=[
    "join #foo #bar #baz" => ["join", "#foo", "#bar", "#baz"],
    "msg person hi" => ["msg", "person", "hi"],
    "msg #channel :hello world" => ["msg", "#channel", "hello world"],
    "help :how do I use IRC" => ["help", "how do I use IRC"],
    "foo bar :baz bip :abc def :ghi :xyz" => ["foo", "bar", "baz bip", "abc def", "ghi", "xyz"],
];
function i($argv_1_){$a=($s=preg_split)("# +:#",$argv_1_);array_splice($a,0,1,$s("# +#",$a[0]));return $a;}
foreach($cases as$x=>$e)
{
    $y=i($x);
    echo "case '$x': ['",join("','",$y),'"]: ',($y<>$e?"FAIL. Expected: ['". join("','",$e)."']":OK),"\n";
}
\$\endgroup\$
  • \$\begingroup\$ what should i learn from that downvote? \$\endgroup\$ – Titus Dec 3 '16 at 12:53
  • \$\begingroup\$ I'm not sure why whoever downvoted did as they did, but maybe it didn't work for all test cases? \$\endgroup\$ – Downgoat Dec 3 '16 at 16:46
  • \$\begingroup\$ @Downgoat Or maybe someone just doesn´t like my nose. It doesn´t check the input for correctness; but I don´t see that required anywhere. \$\endgroup\$ – Titus Dec 4 '16 at 12:58
2
\$\begingroup\$

PowerShell v2+, 43 34 bytes

$a,$b=$args-split' +:';-split$a;$b

This -splits the input string $args on the regex +: (i.e., one or more spaces and a colon), stores the left-most (i.e., first result) into $a and any remaining results into $b. We then need to -split $a on spaces (here done by leveraging that whitespace is the default for unary -split), and that's left on the pipeline. We then simply put $b on the pipeline. Output via implicit Write-Output inserts a newline between elements.

Test cases

PS C:\Tools\Scripts\golfing> .\parse-raw-irc.ps1 'join #foo #bar #baz'
join
#foo
#bar
#baz

PS C:\Tools\Scripts\golfing> .\parse-raw-irc.ps1 'msg person hi'
msg
person
hi

PS C:\Tools\Scripts\golfing> .\parse-raw-irc.ps1 'msg channel :hello world'
msg
channel
hello world

PS C:\Tools\Scripts\golfing> .\parse-raw-irc.ps1 'help :how do I use IRC'
help
how do I use IRC

PS C:\Tools\Scripts\golfing> .\parse-raw-irc.ps1 'foo bar :baz bip :abc def :ghi :xyz'
foo
bar
baz bip
abc def
ghi
xyz
\$\endgroup\$
2
\$\begingroup\$

Retina, 24 bytes

M!`:.+?(?=\s+:|$)|\S+
:

(note there is a trailing newline)

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Added that new line. Could you pop an explanation in at some point? \$\endgroup\$ – Jonathan Allan Dec 6 '16 at 15:25
1
\$\begingroup\$

JavaScript (ES6), 59 57 56 49 bytes

This is my first entry on PPCG, any input appreciated!

(s,[a,...b]=s.split(/ +:/))=>a.split` `.concat(b)

EDIT History:

  • Thanks @Mego for saving 2 bytes by making it an anonymous function.

  • Replaced \s with   to save 1 byte.

  • Thanks @BassdropCumberwubwubwub for showing me the split` ` syntax and the [a,...b]=array_expression_here syntax. I didn't know these were possible, thank you very much! Very clever!

Test snippet

let f = (s,[a,...b]=s.split(/ +:/))=>a.split` `.concat(b)
<input id=I type="text" size=70 value="command arg1 arg2 :arg3 with spaces :arg4 with spaces :arg5"><button onclick="console.log(f(I.value))">Run</button>

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG! The only improvement I see is that you can drop the f= to make it an anonymous function, which are allowed on the site by default. \$\endgroup\$ – Mego Dec 5 '16 at 0:07
  • 1
    \$\begingroup\$ You can write split(" ") as split` ` to save 2 bytes \$\endgroup\$ – Bassdrop Cumberwubwubwub Dec 5 '16 at 16:11
  • \$\begingroup\$ Actually, even shorter like this (s,[a,...b]=s.split(/ +:/))=>a.split` `.concat(b) \$\endgroup\$ – Bassdrop Cumberwubwubwub Dec 6 '16 at 16:32
0
\$\begingroup\$

Mathematica, 44 bytes

Flatten@MapAt[s=StringSplit,#,1]&@s[#," :"]&
\$\endgroup\$
0
\$\begingroup\$

C, 140 bytes (excluding sample usage)

void p(char*m){char*c=strchr(m,':');if(c) {*c=0;c++;} 
char*n=strtok(m," ");while(n) {puts(n);n=strtok(NULL," ");}
if(c){puts(c);}}

Sample usage:

#include <string.h>
#include <stdio.h>
void parse(char*msg){char*c=strchr(msg,':');if(c) {*c=0;c++;} 
char*n=strtok(msg," ");while(n){puts(n);n=strtok(NULL," ");}
if(c){puts(c);}}
main(){char msg[]="sample : abcnsjd hajs";parse(msg);}

Try me: http://codepad.org/GQ51MO4l

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG! :) First of all, you should format your golfed code the same way as your 'sample usage' code. You could turn every name that is over 1 characters to 1, ex. parse to p and msg to m. Useless whitespaces could be removed from after if(c) (both cases) and while(n). \$\endgroup\$ – Yytsi Dec 4 '16 at 13:37
  • \$\begingroup\$ I count 131 bytes, and there's still extraneous whitespace. \$\endgroup\$ – Mego Dec 19 '16 at 5:08
0
\$\begingroup\$

Python 2, 64 60 bytes

import re;a=re.split(' +:',input());print a[0].split()+a[1:]

Edit:
Requires quoted input to use input.
Preserves trailing spaces on last argument.

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

Perl 6,  49  47 bytes

{m/(<-[\ :]>+)+%%" "+":"?(.+?)*%[" "+":"]$/.flat}

Perl 6 version of the Python answer

{$/=.split(/" "+":"/);|$0.split(" "),|$/[1..*]}

The to |s are there to flatten the list.

the first entry expanded:

{    # bare block lambda with implicit parameter 「$_」

  m/               # regex match implicitly against 「$_」

      (               # capture
        <-[\ :]>+     # at least one non-space non-colon character
      )+              # at least once

    %%                # separated (with optional trailing separator)

      " "+            # by at least one space


    ":"?              # optionally match a colon ( needed for rest of regex )


      (               # capture
        .+?           # at least one character as short as possible
      )*              # any number of times

    %                 # separated (no optional trailing separator)

      [ " "+ ":" ]    # by at least one space, and a colon


    $                 # match end of string (needed because of 「.+?」)
  /

 .flat         # flatten the captures
}
\$\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.