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\$
10
  • \$\begingroup\$ Could the final argument end with spaces? \$\endgroup\$ Dec 3, 2016 at 0:16
  • \$\begingroup\$ @JonathanAllan Yes \$\endgroup\$
    – user45941
    Dec 3, 2016 at 1:43
  • \$\begingroup\$ Can we assume that input will be valid? \$\endgroup\$
    – Titus
    Dec 4, 2016 at 12:48
  • \$\begingroup\$ @Titus Yes, that was the goal of defining what constitutes valid input. \$\endgroup\$
    – user45941
    Dec 4, 2016 at 23:32
  • \$\begingroup\$ Does the output have to be a flat list? \$\endgroup\$ Dec 8, 2016 at 16:36

9 Answers 9

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\$
3
  • \$\begingroup\$ what should i learn from that downvote? \$\endgroup\$
    – Titus
    Dec 3, 2016 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, 2016 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, 2016 at 12:58
2
\$\begingroup\$

Retina, 24 bytes

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

(note there is a trailing newline)

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Added that new line. Could you pop an explanation in at some point? \$\endgroup\$ Dec 6, 2016 at 15:25
1
\$\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\$
0
\$\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\$
3
  • \$\begingroup\$ How does this handle <space><space>:? \$\endgroup\$
    – isaacg
    Dec 2, 2016 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\$ Dec 3, 2016 at 11:48
  • \$\begingroup\$ I think you can add the Ṙ×0 test harness too. \$\endgroup\$ Dec 4, 2016 at 13:54
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\$
2
  • 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, 2016 at 13:37
  • \$\begingroup\$ I count 131 bytes, and there's still extraneous whitespace. \$\endgroup\$
    – user45941
    Dec 19, 2016 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\$
2
  • \$\begingroup\$ Since we allow input to be wrapped in quotes, you can use input() instead of raw_input() \$\endgroup\$
    – user45941
    Dec 5, 2016 at 21:59
  • \$\begingroup\$ Needs to handle the edge case of the final argument having trailing spaces \$\endgroup\$ Dec 6, 2016 at 15:21
0
\$\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\$
3
  • 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\$
    – user45941
    Dec 5, 2016 at 0:07
  • 1
    \$\begingroup\$ You can write split(" ") as split` ` to save 2 bytes \$\endgroup\$ Dec 5, 2016 at 16:11
  • \$\begingroup\$ Actually, even shorter like this (s,[a,...b]=s.split(/ +:/))=>a.split` `.concat(b) \$\endgroup\$ Dec 6, 2016 at 16:32
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 and acknowledge that you have read and understand our privacy policy and code of conduct.