g | x | w | all
Bytes Lang Time Link
067Raku Perl 6 rakudo250417T162027Zxrs
065AWK250408T162840Zxrs
145Excel220110T200920ZEngineer
244Haskell150717T093252ZJeremy L
6284Taxi210822T163146ZJosiahRy
018Japt S210819T084759ZShaggy
018Stax210819T040834ZRazetime
027Husk210819T034925ZRazetime
018Vyxal210819T001002Zemanresu
177Haskell150804T193440ZLeif Wil
076KDBQ150626T085537ZWooiKent
162Java150618T005536ZGeobits
031CJam150618T004138ZDennis
086JavaScript ES6150618T023326ZNinjaBea
129SAS150618T033222ZFried Eg
275rs150619T163534Zkirbyfan
146C150619T100733Zedc65
019Pyth150619T003243ZJakube
046Perl150618T154059Znutki
184C150618T060327Zsome use
101Bash150618T145628ZDaniel W
097Julia150618T030343ZAlex A.
116JavaScript150618T123308ZC5H8NNaO
084Python 2150618T041123ZKade
068Ruby150618T003230ZDoorknob
092PHP4.1150618T093457ZIsmael M
078Python 2150618T084947Zxnor
164SpecBAS150618T084124ZBrian
022Pyth150618T012827Zizzyg
118R150618T021414ZMickyT

Raku (Perl 6) (rakudo), 67 bytes

{$!=$^a;for <NBM BM NB M B N> ->$x {$_~=+($!~~s:g/$x//)~$x~' '};$_}

Attempt This Online!

I'm convinced there's a shorter way with map...

{$!=$^a;           # incoming parameters are r/o
for                # for each member of
<NBM BM NB M B N>  # this array
 ->$x              # name the member
{$_~=              # append to a string
+                  # coerce to int
($!~~s:g/$x//)     # return number of subs
~$x                # append member
~' '}              # append space
;$_}               # return final string

AWK, 65 bytes

{for(;i++<split("NBM BM NB M B N",a);)s=gsub(d=a[i],FS)d" "s}$0=s

Attempt This Online!

{for(                        # loop search strings
;i++<                        # each string
split("NBM BM NB M B N",a);) # search strings                  
s=                           # craft new string
gsub(d=a[i],FS)              # return number of matches
d" "                         # append search string
s}                           # to front of string
$0=s                         # set output to string

Excel, 149 145 bytes

Saved 4 bytes by realizing I can directly use LEN(a) after I rewrote the function from my first - never submitted - draft.

=LET(a,SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"NBM",1),"BM",2),"NB",3),LEN(a)-LEN(SUBSTITUTE(a,{"N","B","M",3,2,1},))&{"N","B","M","NB","BM","NBM"})

Start by replacing NBM with 1 then BM with 2 and NB with 3. Now we have a string that is as many characters long as they are creatures. One by one, we check the difference between that string's length and it's length with one of the creatures removed. Output is an array of cells.

Screenshot

Haskell, 244 bytes

import Data.List
s="NBM"
[]#_=[[]]
a#[]=[]:a#s
l@(a:r)#(b:m)
 |a==b=let(x:y)=r#m in((a:x):y)
 |True=[]:l#m
c?t=length$filter(==t)c
p=["N","B","M","NB","BM","NBM"]
main=getLine>>= \l->putStrLn.intercalate " "$map(\t->show((l#[])?t)++t)p

Taxi, 6284 bytes

Go to Post Office:W 1 L 1 R 1 L.Pickup a passenger going to Chop Suey.Go to Chop Suey:N 1 R 1 L 4 R 1 L.[A]Switch to plan N if no one is waiting.Pickup a passenger going to Cyclone.N is waiting at Writer's Depot.Go to Zoom Zoom:N 1 L 3 R.Go to Writer's Depot:W.Pickup a passenger going to Crime Lab.Go to Cyclone:N.Pickup a passenger going to Cyclone.Go to Cyclone:N 1 R 1 R 1 R.Pickup a passenger going to Cyclone.Pickup a passenger going to Cyclone.Go to Cyclone:N 1 R 1 R 1 R.Pickup a passenger going to Tom's Trims.Pickup a passenger going to Tom's Trims.Go to Tom's Trims:S 1 L 2 R 1 L.Go to Cyclone:S 1 R 1 L 2 R.Pickup a passenger going to Crime Lab.Pickup a passenger going to Tom's Trims.Go to Tom's Trims:S 1 L 2 R 1 L.Go to Crime Lab:S 1 L 1 L.Switch to plan F if no one is waiting.Pickup a passenger going to Auctioneer School.Go to Rob's Rest:S 1 R 1 L 1 L 1 R 1 R.Switch to plan D if no one is waiting.Go to Bird's Bench:S.Switch to plan B if no one is waiting.Go to Rob's Rest:N.Pickup a passenger going to KonKat's.Go to Bird's Bench:S.Pickup a passenger going to KonKat's.Go to KonKat's:N 1 R 1 L 2 R 1 R 2 R.Pickup a passenger going to Sunny Skies Park.Go to Sunny Skies Park:N 1 L 2 L 1 L.Go to Auctioneer School:S.Pickup a passenger going to Rob's Rest.Go to Rob's Rest:N 2 L 1 R.Go to Cyclone:S 1 L 1 L 2 L.Switch to plan C.[B]Go to Auctioneer School:N 1 R 1 R.Pickup a passenger going to Sunny Skies Park.Go to Sunny Skies Park:N.Go to Cyclone:N 1 L.[C]Pickup a passenger going to Riverview Bridge.Go to Riverview Bridge:N 2 R.Go to Chop Suey:E 2 R.Switch to plan A.[D]Go to Bird's Bench:S.Switch to plan E if no one is waiting.Pickup a passenger going to Sunny Skies Park.[E]Go to Auctioneer School:N 1 R 1 R.Pickup a passenger going to Rob's Rest.Go to Rob's Rest:N 2 L 1 R.Go to Sunny Skies Park:S 1 L 1 L.Go to Cyclone:N 1 L.Switch to plan C.[F]B is waiting at Writer's Depot.Go to Writer's Depot:S 1 R 1 L 2 L.Pickup a passenger going to Crime Lab.Go to Cyclone:N.Pickup a passenger going to Cyclone.Go to Cyclone:N 1 R 1 R 1 R.Pickup a passenger going to Crime Lab.Go to Crime Lab:S 1 L 2 R 2 L.Switch to plan J if no one is waiting.Pickup a passenger going to Auctioneer School.Go to Bird's Bench:S 1 R 1 L 1 L 1 R 1 L.Switch to plan I if no one is waiting.Go to Rob's Rest:N.Switch to plan G if no one is waiting.Pickup a passenger going to KonKat's.[G]Go to Bird's Bench:S.Pickup a passenger going to KonKat's.Go to KonKat's:N 1 R 1 L 2 R 1 R 2 R.Pickup a passenger going to Sunny Skies Park.Go to Sunny Skies Park:N 1 L 2 L 1 L.Go to Auctioneer School:S.[H]Pickup a passenger going to Bird's Bench.Go to Bird's Bench:N 2 L 1 L.Go to Cyclone:N 1 R 1 L 2 L.Switch to plan C.[I]Go to Auctioneer School:N 1 R 1 R.Switch to plan H.[J]Go to Bird's Bench:S 1 R 1 L 1 L 1 R 1 L.Switch to plan L if no one is waiting.Go to Rob's Rest:N.Switch to plan K if no one is waiting.Pickup a passenger going to KonKat's.[K]Go to Bird's Bench:S.Pickup a passenger going to KonKat's.[L]Go to Cyclone:N 1 R 1 L 2 L.Pickup a passenger going to KonKat's.Go to KonKat's:N 2 R 2 R.Pickup a passenger going to Sunny Skies Park.Go to Rob's Rest:S 4 R 1 L 1 L 1 R 1 R.Switch to plan M if no one is waiting.Pickup a passenger going to Sunny Skies Park.[M]Go to Sunny Skies Park:S 1 L 1 L.Go to Chop Suey:N 1 R 1 R 3 R.Switch to plan A.[N]Go to Rob's Rest:N 1 L 3 L 1 L 2 R 1 R.Switch to plan O if no one is waiting.Pickup a passenger going to KonKat's.[O]Go to Bird's Bench:S.Switch to plan P if no one is waiting.Pickup a passenger going to KonKat's.[P]Go to KonKat's:N 1 R 1 L 2 R 1 R 2 R.Switch to plan Q if no one is waiting.Pickup a passenger going to Sunny Skies Park.[Q]Go to Sunny Skies Park:N 1 L 2 L 1 L.N is waiting at Writer's Depot.B is waiting at Writer's Depot.M is waiting at Writer's Depot.NB is waiting at Writer's Depot.BM is waiting at Writer's Depot.NBM is waiting at Writer's Depot.Go to Writer's Depot:N 1 L.Pickup a passenger going to Joyless Park.Pickup a passenger going to Joyless Park.Pickup a passenger going to Joyless Park.Go to Joyless Park:N 3 R 2 R 2 L.Go to Writer's Depot:W 1 R 2 L 2 L.Pickup a passenger going to Joyless Park.Pickup a passenger going to Joyless Park.Pickup a passenger going to Joyless Park.Go to Joyless Park:N 3 R 2 R 2 L.[R]Switch to plan Y if no one is waiting.Pickup a passenger going to Cyclone.0 is waiting at Starchild Numerology.Go to Starchild Numerology:W 1 L 2 R 1 L 1 L 2 L.Pickup a passenger going to Addition Alley.Go to Cyclone:W 1 R 4 L.[S]Pickup a passenger going to Auctioneer School.Go to Zoom Zoom:N.Go to Auctioneer School:W 2 L.Go to Sunny Skies Park:N.Switch to plan V if no one is waiting.Pickup a passenger going to Cyclone.Go to Cyclone:N 1 L.Pickup a passenger going to Crime Lab.Pickup a passenger going to Crime Lab.Go to Crime Lab:S 1 L 2 R 2 L.Switch to plan T if no one is waiting.Pickup a passenger going to Tom's Trims.Go to Tom's Trims:N 1 L 1 L.1 is waiting at Starchild Numerology.Go to Starchild Numerology:S 1 R 1 L 1 L 2 L.Pickup a passenger going to Addition Alley.Go to Addition Alley:W 1 R 3 R 1 R 1 R.Pickup a passenger going to Addition Alley.Go to Cyclone:N 1 L 1 L.Pickup a passenger going to Riverview Bridge.Go to Riverview Bridge:N 2 R.Go to Auctioneer School:W 2 L 1 L.Switch to plan U.[T]Go to Cyclone:N 4 L 2 L.Pickup a passenger going to Narrow Path Park.Go to Narrow Path Park:N 2 R 1 L 1 R.Go to Auctioneer School:W 1 L 1 R 2 L 1 L.[U]Pickup a passenger going to Cyclone.Go to Cyclone:N 4 L.Switch to plan S.[V]Go to Addition Alley:N 1 R 1 R 1 R.Pickup a passenger going to The Babelfishery.Go to The Babelfishery:N 1 R 1 R.Pickup a passenger going to Post Office.Go to Cyclone:N 1 L 1 L 2 R.Pickup a passenger going to Post Office." " is waiting at Writer's Depot.Go to Writer's Depot:S.Pickup a passenger going to Post Office.Go to Post Office:N 1 R 2 R 1 L.Go to Auctioneer School:S 1 R 1 L 1 L.Pickup a passenger going to Tom's Trims.Go to Narrow Path Park:N 3 R 1 R 1 L 1 R.[W]Switch to plan X if no one is waiting.Pickup a passenger going to Sunny Skies Park.Go to Sunny Skies Park:W 1 L 1 R 2 L 1 L.Go to Zoom Zoom:N 1 R.Go to Narrow Path Park:W 1 L 1 L 1 R.Switch to plan W.[X]Go to Tom's Trims:E 1 R 4 R 1 L.Go to Joyless Park:N 1 R 1 L 3 R.Switch to plan R.[Y]

Try it online!

This ain't winning me any Code Golf competitions, but this was a nice reminder for me not to write any more complex programs in Taxi. (Sooo many special cases, and sooo much gas management...)

A more commented version can be found here, if you dare.

Japt -S, 18 bytes

Outputs in reverse order.

"NBM"ã ÔËiUèDU=rDS

Try it (footer reverses the output)

"NBM"ã ÔËiUèDU=rDS     :Implicit input of string U
"NBM"ã                 :Substrings of "NBM"
       Ô               :Reverse
        Ë              :Map each D
         i             :  Prepend
          UèD          :    Count of D in U
             U=        :    Reassign to U*
               rD      :      Replace D with
                 S     :      Space
                       :Implicit output joined with spaces

*This is done within the second argument of the è method but as that only expects 1 argument, it's result is ignored within the mapping & prepending.

Stax, 18 bytes

â╥)3╨‼!∩╢←◘♀←N╟Ijƒ

Run and debug it

Husk, 27 bytes

;zS`+ös←Lx₁GoΣ`x⁰₁
↔ÖLQ"NBM

Try it online!

uses the splitting technique from the Vyxal answer.

Husk, 28 bytes

m§+osL←k€₁Ẋ`-U¡Ṡ-(→n₁ḣ
Q"NBM

Try it online!

Funny set intersection based idea.

Vyxal, 18 bytes

`NBM`KṘ(n/₅‹n+¨…_∑

Try it Online!

`NBM`              # 'NBM'
     K             # Substrings
      Ṙ(           # Iterate over
        n/         # Split current string by current substring of NBM
          ₅‹       # Duplicate and decrement length
            np¨…_  # Prepend current substring of NBM and output with a trailing space
                 ∑ # Concatenate for next iteration

Haskell - 177 bytes (without imports)

n s=c$map(\x->(show$length$filter(==x)(words$c$zipWith(:)s([f(a:[b])|(a,b)<-zip s(tail s)]++[" "])))++x++" ")l
f"NB"=""
f"BM"=""
f p=" "
l=["N","B","M","NB","BM","NBM"]
c=concat

(Sorry for the internet necromancy here.)

The Haskell Platform doesn't have string search without imports, and I wanted to show off and exploit the fact that the searched strings are all substrings of one (without repetitions), so that grouping characters can be done by identifying pairs that are allowed to follow each other, which is what f does here.

I still need the full list l in the end to check for equality and display exactly as required, but would not, had the challenge only been to report the number of occurrences of the possible words in any order.

KDB(Q), 76 bytes

{" "sv string[-1+count@'enlist[x]{y vs" "sv x}\l],'l:" "vs"NBM NB BM N B M"}

Explanation

                                                   l:" "vs"NBM NB BM N B M"     / substrings
                        enlist[x]{y vs" "sv x}\l                                / replace previous substring with space and cut
              -1+count@'                                                        / counter occurrence
       string[                                  ],'                             / string the count and join to substrings
{" "sv                                                                     }    / concatenate with space, put in lambda

Test

q){" "sv string[-1+count@'enlist[x]{y vs" "sv x}\l],'l:" "vs"NBM NB BM N B M"}"NNNMNBMMBMMBMMMNBMNNMNNNBNNNBNBBNBNMMNBBNBMMBBMBMBBBNNMBMBMMNNNNNMMBMMBM"
"3NBM 5NB 8BM 17N 6B 14M"
q){" "sv string[-1+count@'enlist[x]{y vs" "sv x}\l],'l:" "vs"NBM NB BM N B M"}""
"0NBM 0NB 0BM 0N 0B 0M"

Java, 166 162

void f(String a){String[]q="NBM-NB-BM-N-B-M".split("-");for(int i=0,c;i<6;System.out.print(c+q[i++]+" "))for(c=0;a.contains(q[i]);c++)a=a.replaceFirst(q[i],".");}

And with a few line breaks:

void f(String a){
    String[]q="NBM-NB-BM-N-B-M".split("-");
    for(int i=0,c;i<6;System.out.print(c+q[i++]+" "))
        for(c=0;a.contains(q[i]);c++)
            a=a.replaceFirst(q[i],".");
}

It works pretty simply. Just loop over the tokens, replacing them with dots and counting as long as the input contains some. Counts the big ones first, so the little ones don't mess it up.

I originally tried replacing all at once and counting the difference in length, but it took a few more characters that way :(

CJam, 36 32 31 bytes

l[ZYX]"NBM"few:+{A/_,(A+S@`}fA;

Thanks to @Optimizer for golfing off 1 byte.

Try it online in the CJam interpreter.

How it works

l                                e# Read a line L from STDIN.
 [ZYX]"NBM"                      e# Push [3 2 1] and "NBM".
           few                   e# Chop "NBM" into slices of length 3 to 1.
              :+                 e# Concatenate the resulting arrays of slices.
                {          }fA   e# For each slice A:
                 A/              e#   Split L at occurrences of A.
                   _,(           e#   Push the numbers of resulting chunks minus 1.
                      A+         e#   Append A.
                        S        e#   Push a space.
                         @`      e#   Push a string representation of the split L.
                              ;  e# Discard L.

JavaScript ES6, 86 bytes

f=s=>'NBM BM NB M B N'.replace(/\S+/g,e=>(i=0,s=s.replace(RegExp(e,'g'),_=>++i))&&i+e)

(I just had to answer this.) It goes through each substring of NBM, starting with the longer ones, which take higher priority. It searches for each occurrence of that particular string and removes it (in this case replacing it with the current count so it won't be matched again). It finally replaces each substring with the count + the string.

This Stack Snippet is written in the ES5 equivalent of the above code to make it easier to test from any browser. It is also slightly ungolfed code. The UI updates with every keystroke.

f=function(s){
  return'NBM BM NB M B N'.replace(/\S+/g,function(e){
    i=0
    s=s.replace(RegExp(e,'g'),function(){
      return++i
    })
    return i+e
  })
}

run=function(){document.getElementById('output').innerHTML=f(document.getElementById('input').value)};document.getElementById('input').onkeyup=run;run()
<input type="text" id="input" value="NBMMBNBNBM" /><br /><samp id="output"></samp>

SAS, 144 142 139 129

data;i="&sysparm";do z='NBM','NB','BM','N','B','M';a=count(i,z,'t');i=prxchange(cats('s/',z,'/x/'),-1,i);put a+(-1)z@;end;

Usage (7 bytes added for sysparm):

$ sas -stdio -sysparm NNNMNBMMBMMBMMMNBMNNMNNNBNNNBNBBNBNMMNBBNBMMBBMBMBBBNNMBMBMMNNNNNMMBMMBM << _S
data;i="&sysparm";do z='NBM','NB','BM','N','B','M';a=count(i,z,'t');i=prxchange(cats('s/',z,'/x/'),-1,i);put a+(-1)z@;end;
_S

or

%macro f(i);i="&i";do z='NBM','NB','BM','N','B','M';a=count(i,z,'t');i=prxchange(cats('s/',z,'/x/'),-1‌​,i);put a+(-1)z@;end;%mend;

Usage:

data;%f(NNNMNBMMBMMBMMMNBMNNMNNNBNNNBNBBNBNMMNBBNBMMBBMBMBBBNNMBMBMMNNNNNMMBMMBM)

Result:

3NBM 5NB 8BM 17N 6B 14M

rs, 275 bytes

(NBM)|(NB)|(BM)|(N)|(B)|(M)/a\1bc\2de\3fg\4hi\5jk\6l
[A-Z]+/_
#
+(#.*?)a_b/A\1
+(#.*?)c_d/B\1
+(#.*?)e_f/C\1
+(#.*?)g_h/D\1
+(#.*?)i_j/E\1
+(#.*?)k_l/F\1
#.*/
#
#(A*)/(^^\1)NBM #
#(B*)/(^^\1)NB #
#(C*)/(^^\1)BM #
#(D*)/(^^\1)N #
#(E*)/(^^\1)B #
#(F*)/(^^\1)M #
\(\^\^\)/0
 #/

Live demo and tests.

The workings are simple but a little odd:

(NBM)|(NB)|(BM)|(N)|(B)|(M)/a\1bc\2de\3fg\4hi\5jk\6l

This creatively uses groups to turn input like:

NBMBM

into

aNBMbcdeBMfghijkl

The next line:

[A-Z]+/_

This replaces the sequences of capital letters with underscores.

#

This simply inserts a pound sign at the beginning of the line.

+(#.*?)a_b/A\1
+(#.*?)c_d/B\1
+(#.*?)e_f/C\1
+(#.*?)g_h/D\1
+(#.*?)i_j/E\1
+(#.*?)k_l/F\1
#.*/

This is the beginning cool part. It basically takes the sequences of lowercase letters and underscores, converts them into capital letters, groups them together, and places them before the pound that was inserted. The purpose of the pound is to manage the sequences that have already been processed.

#

The pound is re-inserted at the beginning of the line.

#(A*)/(^^\1)NBM #
#(B*)/(^^\1)NB #
#(C*)/(^^\1)BM #
#(D*)/(^^\1)N #
#(E*)/(^^\1)B #
#(F*)/(^^\1)M #
\(\^\^\)/0
 #/

The capital letters are replaced by their text equivalents with the associated counts. Because of a bug in rs (I didn't want to risk fixing it and getting disqualified), the empty sequences are converted into (^^), which is replaced by a 0 in the second-to-last line. The very last line simply removes the pound.

C, 146

f(char*s)
{
  char*p,*q="NBM\0NB\0BM\0N\0B\0M",i=0,a=2;
  for(;i<6;q+=a+2,a=i++<2)
  {
    int n=0;
    for(;p=strstr(s,q);++n)*p=p[a>1]=p[a]=1;
    printf("%d%s ",n,q);
  }
}

// Main function, just for testing
main(c,a)char**a;{
  f(a[1]);
}  

Pyth, 19 bytes

jd+Ltl=zc`zd_.:"NBM

This is a mixture of @isaacg's Pyth solution and @xnor's incredible Python trick.

Try it online: Demonstration or Test harness

Explanation

jd+Ltl=zc`zd_.:"NBM   implicit: z = input string
             .:"NBM   generate all substrings of "NBM"
            _         invert the order
  +L                  add left to each d in ^ the following:
         `z             convert z to a string
        c  d            split at d
      =z                assign the resulting list to z
    tl                  length - 1
jd                    join by spaces and implicit print

Perl, 46

#!perl -p
$_="NBM BM NB M B N"=~s/\w+/~~s!$&!x!g.$&/ger

C, 205 186 184 bytes

A little different approach based on state machine. where t is the state.

a[7],t,i;c(char*s){do{i=0;t=*s==78?i=t,1:*s-66?*s-77?t:t-4?t-2?i=t,3:5:6:t-1?i=t,2:4;i=*s?i:t;a[i]++;}while(*s++);printf("%dN %dB %dM %dNB %dBM %dNBM",a[1],a[2],a[3],a[4],a[5],a[6]);}

Expanded

int a[7],t,i;

void c(char *s)
{
    do {
        i = 0;
        if (*s == 'N') {
            i=t; t=1;
        }
        if (*s == 'B') {
            if (t==1) {
                t=4;
            } else {
                i=t;
                t=2;
            }
        }
        if (*s == 'M') {
            if (t==4) {
                t=6;
            } else if (t==2) {
                t=5;
            } else {
                i=t;
                t=3;
            }
        }
        if (!*s)
            i = t;
        a[i]++;
    } while (*s++);
    printf("%dN %dB %dM %dNB %dBM %dNBM",a[1],a[2],a[3],a[4],a[5],a[6]);
}

Test function

#include <stdio.h>
#include <stdlib.h>

/*
 * 0 : nothing
 * 1 : N
 * 2 : B
 * 3 : M
 * 4 : NB
 * 5 : BM
 * 6 : NBM
 */
#include "nbm-func.c"

int main(int argc, char **argv)
{
    c(argv[1]);
}

Bash - 101

I=$1
for p in NBM BM NB M B N;{ c=;while [[ $I =~ $p ]];do I=${I/$p/ };c+=1;done;echo -n ${#c}$p\ ;}

Pass the string as the first argument.

bash nmb.sh MBNNBBMNBM 

Explained a bit:

# We have to save the input into a variable since we modify it.
I=$1

# For each pattern (p) in order of precedence
for p in NBM BM NB M B N;do
    # Reset c to an empty string
    c=

    # Regexp search for pattern in string
    while [[ $I =~ $p ]];do
        # Replace first occurance of pattern with a space
        I=${I/$p/ }
        # Append to string c. the 1 is not special it could be any other
        # single character
        c+=1
    done

    # -n Suppress's newlines while echoing
    # ${#c} is the length on the string c
    # Use a backslash escape to put a space in the string.
    # Not using quotes in the golfed version saves a byte.
    echo -n "${#c}$p\ "
done

Julia, 106 97 bytes

b->for s=split("NBM BM NB M B N") print(length(matchall(Regex(s),b)),s," ");b=replace(b,s,".")end

This creates an unnamed function that takes a string as input and prints the result to STDOUT with a single trailing space and no trailing newline. To call it, give it a name, e.g. f=b->....

Ungolfed + explanation:

function f(b)
    # Loop over the creatures, biggest first
    for s = split("NBM BM NB M B N")

        # Get the number of creatures as the count of regex matches
        n = length(matchall(Regex(s), b))

        # Print the number, creature, and a space
        print(n, s, " ")

        # Remove the creature from captivity, replacing with .
        b = replace(b, s, ".")
    end
end

Examples:

julia> f("NBMMBNBNBM")
2NBM 0BM 1NB 1M 1B 0N 

julia> f("NNNMNBMMBMMBMMMNBMNNMNNNBNNNBNBBNBNMMNBBNBMMBBMBMBBBNNMBMBMMNNNNNMMBMMBM")
3NBM 8BM 5NB 14M 6B 17N 

JavaScript, 108 116 bytes

Just a straight forward approach, nothing fancy

o="";r=/NBM|NB|BM|[NMB]/g;g={};for(k in d=(r+prompt()).match(r))g[d[k]]=~-g[d[k]];for(k in g)o+=~g[k]+k+" ";alert(o);

Python 2, 93 88 89 84 Bytes

Taking the straightforward approach.

def f(n):
 for x in"NBM BM NB M B N".split():print`n.count(x)`+x,;n=n.replace(x,"+")

Call like so:

f("NBMMBNBNBM")

Output is like so:

2NBM 0BM 1NB 1M 1B 0N

Ruby, 166 80 72 68 characters

f=->s{%w(NBM BM NB M B N).map{|t|c=0;s.gsub!(t){c+=1};c.to_s+t}*' '}

Explanation:


Similar solution in Ostrich, 54 51 chars:

:s;`NBM BM NB M B N`" /{:t0:n;s\{;n):n}X:s;nt+}%" *

Unfortunately not a valid solution, as there is a bug in the current Ostrich version (that is now fixed, but after this challenge was posted).

PHP4.1, 92 bytes

Not the shortest one, but what else would you expect from PHP?

To use it, set a key on a COOKIE, POST, GET, SESSION...

<?foreach(split(o,NBMoNBoBMoMoBoN)as$a){echo count($T=split($a,$S))-1,"$a ";$S=join('',$T);}

The apporach is basic:

Easy, right?

Python 2, 78

n=input()
for x in"NBM BM NB M B N".split():n=`n`.split(x);print`len(n)-1`+x,

A variant of Vioz-'s answer. Fun with Python 2 string representations!

Counts occurrences of the substring indirectly by splitting on it, counting the parts, and subtracting 1. Instead of replacing the substrings by a filler symbol, replaces the string by the list that split produced. Then, when we take its string representation, the parts are separated by spaces and commas.

SpecBAS - 164

1 INPUT s$
2 FOR EACH a$ IN ["NBM","BM","NB","M","B","N"]
3 LET n=0
4 IF POS(a$,s$)>0 THEN INC n: LET s$=REPLACE$(s$,a$,"-"): GO TO 4: END IF
5 PRINT n;a$;" ";
6 NEXT a$

Uses the same approach as a lot of others. Line 4 keeps looping over the string (from largest first), replaces it if found.

SpecBAS has some nice touches over original ZX/Sinclair BASIC (looping through lists, finding characters) which I'm still finding out.

Pyth, 22 bytes

 f|pd+/zTT=:zTd_.:"NBM

Quite hackish way to save 1 byte, thanks to @Jakube.


Pyth, 23 bytes

FN_.:"NBM")pd+/zNN=:zNd

Demonstration.

Prints in reverse order, with a trailing space and no trailing newline.

.:"NBM") is all the substrings, _ puts them in the right order, /zN counts occurences, and =:zNd in-place substitutes each occurence of the string in question with a space.

FN_.:"NBM")pd+/zNN=:zNd
FN                         for N in                            :
  _                                 reversed(                 )
   .:     )                                  substrings(     )
     "NBM"                                              "NBM"
           pd              print, with a space at the end,
              /zN          z.count(N)
             +   N                    + N
                  =:zNd    replace N by ' ' in z.

R, 153 134 118

This got longer really quickly, but hopefully I'll be able to shave a few. Input is STDIN and output to STDOUT.

Edit Change of tack. Got rid of the split string and counting parts. Now I replace the parts with a string one shorter than the part. The difference between the string lengths is collected for output.

N=nchar;i=scan(,'');for(s in scan(,'',t='NBM BM NB M B N'))cat(paste0(N(i)-N(i<-gsub(s,strtrim('  ',N(s)-1),i)),s),'')

Explanation

N=nchar;
i=scan(,'');                     # Get input from STDIN
for(s in scan(,'',t='NBM BM NB M B N'))  # Loop through patterns
  cat(                           # output
    paste0(                      # Paste together
      N(i) -                     # length of i minus
      N(i<-gsub(                 # length of i with substitution of
        s,                       # s
        strtrim('  ',N(s)-1)     # with a space string 1 shorter than s
        ,i)                      # in i
      ),
      s)                         # split string
  ,'')

Test run

> N=nchar;i=scan(,'');for(s in scan(,'',t='NBM BM NB M B N'))cat(paste0(N(i)-N(i<-gsub(s,strtrim('  ',N(s)-1),i)),s),'')
1: NNNMNBMMBMMBMMMNBMNNMNNNBNNNBNBBNBNMMNBBNBMMBBMBMBBBNNMBMBMMNNNNNMMBMMBM
2: 
Read 1 item
Read 6 items
3NBM 8BM 5NB 14M 6B 17N 
> N=nchar;i=scan(,'');for(s in scan(,'',t='NBM BM NB M B N'))cat(paste0(N(i)-N(i<-gsub(s,strtrim('  ',N(s)-1),i)),s),'')
1: NBMMBNBNBM
2: 
Read 1 item
Read 6 items
2NBM 0BM 1NB 1M 1B 0N 
>