20
\$\begingroup\$

Introduction

My car speedometer was hacked! Instead of showing me how fast i'm driving, it just shows: "Vroooom!" Please help me know how fast i'm going.

Challenge

Take a string as input, and check if it matches the regex /^[Vv]ro*m!$/m. In English that means any line of the string must start with a capital or lowercase v, then a lowercase r, then any amount (including zero) of the lowercase letter o, then the exact string m!. There may be other lines, but the Vroom string must be on it's own line.

If you find a match, then you must count the amount of o's in the Vroom string and output it. If you don't find a match however, you should output any default value that can't be outputted otherwise (like -1 or an empty string)

Reminders

Scoring

This is , so the shortest code in bytes wins. However, I will not mark any answer as accepted.

Test cases

Input

Vrom!

Output 1

Input

vrooooooom!

Output 7

Input

Hello, Vroom!

Output (none)

Input

Foo bar boo baz
Vrooom!
hi

Output 3

Input

Vrm!ooo

Output (none)

Input

PPCG puzzlers pie

Output (none)

Input

hallo
vROOOm!

Output (none)

\$\endgroup\$
0

32 Answers 32

8
\$\begingroup\$

sed 4.2.2, 20 bytes

-nr options required at the command-line.

s/^[Vv]r(o*)m!$/\1/p

This outputs the speed in unary as the number of os.

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Can't tell Vrm! from Vram! \$\endgroup\$
    – l4m2
    Nov 3, 2018 at 8:56
4
\$\begingroup\$

Python 2, 56 53 bytes

lambda x:len(re.search('^[Vv]r(o*)m!$',x,8).group(1))

Try it online!

Basic regex and grouping, uses re.MULTILINE flag (which has a value of 8) and re.search to ensure it works for multiline inputs. Raises an exception when no match is found. Thanks to @ovs for the -3 bytes from (re.M == 8) tip.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to PPCG! I reformatted your answer to make it appear a bit nicer, if you're unhappy with my edit you can always roll back. Btw. I suggest to link to something like tio.run such that people can easily test your answer. \$\endgroup\$ Nov 2, 2018 at 20:30
  • \$\begingroup\$ re.M has the value 8, so can just use re.search(regex,x,8) \$\endgroup\$
    – ovs
    Nov 3, 2018 at 16:24
4
\$\begingroup\$

R, 62 60 58 44 bytes

nchar(grep("^[Vv]ro*m!$",readLines(),v=T))-4

Try it online!

@Giuseppe with 14 bytes golfed.

Original approach with explanation:

function(x)attr(el(regexec("(?m)[Vv]r(o*)m!$",x,,T)),"m")[2]

Try it online!

R has seven pattern matching functions. The more commonly used ones are grep, grepl, and sub, but here's a nice use for regexec.

regexec gives you a bunch of things, one of which is the length of any captured substring, in this case the (o*) part of the multiline regex.

The attr(el .... "m")[2] stuff is a golfy way to get the desired number.

Returns NA if there is no match.

\$\endgroup\$
3
  • \$\begingroup\$ 58 bytes with a different approach \$\endgroup\$
    – digEmAll
    Nov 3, 2018 at 15:33
  • \$\begingroup\$ I have a 44 byte approach... Not gonna post it unless you want me to. \$\endgroup\$
    – Giuseppe
    Nov 4, 2018 at 1:53
  • \$\begingroup\$ @Giuseppe not sure why not? Especially if it's fundamentally different. \$\endgroup\$
    – ngm
    Nov 4, 2018 at 2:01
3
\$\begingroup\$

JavaScript (Node.js), 41 bytes

a=>(l=/[Vv]r(o*)m!/.exec(a))&&l[1].length

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ This fails for vroooooooooooom!x\nvrom! \$\endgroup\$ Nov 2, 2018 at 20:27
  • 1
    \$\begingroup\$ Seeing as we're allowed exit with an error if no match is found, you could do this for -3 bytes, fixing the problem @BMO mentioned above in the process. \$\endgroup\$
    – Shaggy
    Nov 2, 2018 at 22:32
  • \$\begingroup\$ Uncrossed-out 41 is definitely still 41 \$\endgroup\$ Nov 3, 2018 at 2:13
  • \$\begingroup\$ @Shaggy What's the space in [1]. length for? \$\endgroup\$
    – l4m2
    Nov 3, 2018 at 8:58
  • \$\begingroup\$ @l4m2, a typo! I didn't spot it on my phone 'cause length was breaking to a newline anyway. \$\endgroup\$
    – Shaggy
    Nov 3, 2018 at 10:53
3
\$\begingroup\$

Powershell, 62 58 53 48 bytes bytes

"$($args|sls '(?m-i)^[Vv]ro*m!$'|% M*)".Length-4

returns numbers of o in a first Vroom!, or -4 if Vroom! not found.

Notes:

  • sls is alias for Select-String;
  • (?m-i) inside regexp means:
    • Use multiline mode. ^ and $ match the beginning and end of a line, instead of the beginning and end of a string.
    • Use case-sensitive matching
  • |% M* is shortcut for the property Matches, which gives a first match because we don't use -AllMatches parameter.

Test script:

$f = {

"$($args|sls '(?m-i)^[Vv]ro*m!$'|% M*)".Length-4

}

@(
,('Vrom!',1)
,('vrooooooom!',7)
,('Hello, Vroom!',-4)
,('Foo bar boo baz
Vrooom!
hi',3)
,('Vrm!ooo',-4)
,('PPCG puzzlers pie',-4)
,('hallo
vROOOm!',-4)
,('
Vrooom!
Vrooooom!
',3)        # undefined behavior.
,('vrm!',0) # :)
) | % {
    $n,$expected = $_
    $result = &$f $n
    "$($result-eq$expected): $result"
}

Output:

True: 1
True: 7
True: -4
True: 3
True: -4
True: -4
True: -4
True: 3
True: 0
\$\endgroup\$
2
\$\begingroup\$

PowerShell, 83 bytes

($args-split"`n"|%{if(($x=[regex]::Match($_,"^[Vv]ro*m!$")).success){$x}}).length-4

Try it online!

-splits the input $args on `newlines, pipes those into a for loop. Each iteration, we check whether our [regex]::Match is a .success or not. If so, we leave $x (the regex results object) on the pipeline. Outside the loop, we take the .length property -- if it's the regex results object, this is the length of the match (e.g., "Vroom!" would be 6); if it's not a regex results object, the length is zero. We then subtract 4 to remove the counts for the Vrm! and leave that on the pipeline. Output is implicit. Outputs a -4 if no match is found.

\$\endgroup\$
4
  • \$\begingroup\$ sls "^[Vv]ro*m!$"? \$\endgroup\$
    – mazzy
    Nov 2, 2018 at 18:58
  • \$\begingroup\$ @mazzy How would that work for multiline input? Your only input is one string, and so sls will give back ('','Vroom!','') for example. \$\endgroup\$ Nov 2, 2018 at 19:06
  • \$\begingroup\$ it's not completed solution. I mean, you can try sls instead [regex]::Match \$\endgroup\$
    – mazzy
    Nov 2, 2018 at 19:08
  • \$\begingroup\$ @mazzy Maybe you should post it as a separate solution. \$\endgroup\$ Nov 2, 2018 at 19:13
2
\$\begingroup\$

Retina, 21 bytes

L$m`^[Vv]r(o*)m!$
$.1

Try it online! Explanation: L lists matches, so if the regex fails to match then output is empty. $ causes the result to be the substitution rather than the match. m makes it a multiline match (the equivalent to the trailing m in the question). The . in the substitution makes it output the length of the capture in decimal.

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

SNOBOL4 (CSNOBOL4), 99 82 bytes

I	INPUT POS(0) ('V' | 'v') 'r' ARBNO('o') @X 'm!' RPOS(0)	:F(I)
	OUTPUT =X - 2
END

Try it online!

Pretty direct SNOBOL translation of the spec, reads each line until it finds one that matches ^[Vv]ro*m!$, then outputs the length of the o* bit.

Enters an infinite loop if no Vroom! can be found.

\$\endgroup\$
2
  • \$\begingroup\$ Is all that whitespace necessary? Wow. \$\endgroup\$
    – kepe
    Nov 2, 2018 at 18:51
  • 5
    \$\begingroup\$ @FireCubez yep, that's what you get with a 50+ year-old language: weird whitespace requirements. It uses space/tab as concatenation and you must surround operators with whitespace as well. \$\endgroup\$
    – Giuseppe
    Nov 2, 2018 at 18:53
2
\$\begingroup\$

Perl 6, 26 bytes

{-!/^^[V|v]r(o)*m\!$$/+$0}

Try it online!

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

C (gcc), 188 183 bytes

Why use regexes when you can use a state machine instead? :-)

a,b;f(char*s){for(a=b=0;a<5;s++){!a&*s==86|*s=='v'?a++:a==1&*s=='r'?a++:a==2?*s-'o'?*s-'m'?0:a++:b++:a==3&*s==33?a++:!*s&a==4?a++:*s-10?(a=-1):a-4?(a=0):a++;if(!*s)break;}s=a<5?-1:b;}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ 147 \$\endgroup\$
    – ceilingcat
    Feb 27, 2020 at 5:04
1
\$\begingroup\$

Stax, 16 bytes

∞╠mQ╛3mQ->n▀÷↕┐ò

Run and debug it

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

Haskell, 75 71 69 bytes

f s=[length n-2|r<-lines s,n<-scanr(:)"m!"$'o'<$r,v<-"Vv",r==v:'r':n]

Try it online!

No regex. Instead builds all valid Vrooom!-strings up to a sufficient length and compares the lines of the input against them, collecting the number of os in a list. Thus for invalid inputs an empty list is returned.

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

C (gcc), 104 100 bytes

s;main(c,n){for(;gets(&s);sscanf(&s,"v%*[o]%nm%c%c",&n,&c,&c)-1||c-33?:printf("%d",n-2))s=s-768|32;}

Try it online!

Output the n for each valid line, exactly in the requirement(nothing if no valid line, the n if exactly one)

int s; // Use as a char[]
main(c){
  while(gets(&s)) {
    s=s-768|32; // byte 0: 'V'=>'v'; byte 1: 'r'=>'o', 'o'=>'l'
    if (sscanf(&s,"v%[o]m%c%c",&s,&c,&c)==2 && c=='!') {
    // The last '%c' get nothing if it's EndOfLine
      printf("%d",strlen(&s)-1))
    }
  }
}
\$\endgroup\$
3
  • \$\begingroup\$ It's so funny that the regex answer is longer than this \$\endgroup\$ Nov 3, 2018 at 11:12
  • \$\begingroup\$ @WindmillCookies GCC need extra code to support regex \$\endgroup\$
    – l4m2
    Nov 3, 2018 at 11:29
  • \$\begingroup\$ hmm. seems like names related to regexes are extremely long \$\endgroup\$ Nov 3, 2018 at 11:32
1
\$\begingroup\$

Japt, 18 bytes

fè`^[Vv]*m!$` ®èo

Try it online!

Saved a byte by taking input as an array of lines.

Includes an unprintable character between ] and *.

Explanation:

fè                   Get the line(s) that match
  `^[Vv]*m!$`          The provided RegEx with a little compression
              ®èo    Count the number of "o" in that line if it exists
\$\endgroup\$
4
  • 1
    \$\begingroup\$ 19 bytes \$\endgroup\$
    – Shaggy
    Nov 2, 2018 at 22:37
  • \$\begingroup\$ Also 19 bytes \$\endgroup\$
    – Shaggy
    Nov 2, 2018 at 23:13
  • \$\begingroup\$ Actually, as input can be an array of lines, you can knock the first byte off my first comment above. \$\endgroup\$
    – Shaggy
    Nov 3, 2018 at 12:07
  • \$\begingroup\$ @Shaggy I can't find anywhere in the question that specifies that input can be an array of lines, and it doesn't seem to be listed in the default I/O methods that a multiline string can be taken as an array of lines. It seems likely to be reasonable, but I'll wait for confirmation first. \$\endgroup\$ Nov 3, 2018 at 17:34
1
\$\begingroup\$

C (gcc), 138 124 bytes

Here's the boring regex way.

#include<regex.h>
f(char*s){regmatch_t m[9];regcomp(m+2,"^[Vv]r(o*)m!$",5);s=regexec(m+2,s,2,m,0)?-1:m[1].rm_eo-m[1].rm_so;}

Try it online!

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

Pyth, 28 bytes

IJjb.nm:rd0"^vro*m!$"1.z/J\o

Try it online!

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

Pyth, 20 bytes

/R\o:#"^Vro*m!$"1cQb

Outputs as a list containing only the number of 'o's, or an empty list if there's no Vroom.
Try it here

Explanation

/R\o:#"^Vro*m!$"1cQb
                 cQb  Split on newlines.
    :#"^Vro*m!$"1     Filter the ones that match the regex.
/R\o                  Count the `o`s in each remaining element.
\$\endgroup\$
0
\$\begingroup\$

Pip, 21 bytes

a~,`^[Vv]r(o*)m!$`#$1

Try it online!

Match regex ^[Vv]r(o*)m!$ in multiline mode; output length of capture group.

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

sfk, 94 bytes

xex -i -case "_[lstart][char of Vv]r[chars of o]m![lend]_[part 4]o_" +linelen +calc "#text-1" 

Try it online!

Gives -1 when you're not vrooming.

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

Red, 104 bytes

func[s][n:""if parse/case s[opt[thru"^/"]["V"|"v"]"r"copy n any"o""m!"opt["^/"to end]][print length? n]]

Try it online!

A straightforward solution. Red's parse is cool and readable, but too long compared to regex

Red []
f: func [ s ] [
    n: ""
    if parse/case s [
             opt [ thru newline ]
             [ "V" | "v" ]
             "r"
             copy n any "o"
             "m!"
             opt [ newline to end ]
    ] [ print length? n ]
]
\$\endgroup\$
0
\$\begingroup\$

J, 35 bytes

(]{~0<{.)(1{'^[Vv]r(o*)m!'rxmatch])

Returns negative 1 if the pattern doesn't match.

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

JavaScript, 90 73 61 bytes

_=>_.replace(/^[Vv]r(o*)m!$|[^\1]/mg,(m,a)=>a||'').length||-1

Try it online!

Replace characters that are not captured at (o*) with empty string, return length of string containing only "o" or -1 if resulting string is empty.

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

Ruby, 32 bytes

->n{n=~/^[Vv]r(o*)m!$/m;$1.size}

Matches the string to the regex, then uses Ruby's magic regex group variables to get the first group's size.

Call it like so:

x=->n{n=~/^[Vv]r(o*)m!$/m;$1.size}
x["Vrooooooooooooooooooooom!"] # returns 21
\$\endgroup\$
0
\$\begingroup\$

Ruby, 28 29 bytes

p$_[/^[vV]r(o*)m!$/].count ?o

Try it online!

Multi-line strings require three more bytes. I'm not sure if that's a hard requirement. If so, I'll update this.

->l{l[/^[Vv]r(o*)m!$/].count ?o}
\$\endgroup\$
2
  • \$\begingroup\$ How can you test multi-line strings? \$\endgroup\$
    – Laikoni
    Nov 3, 2018 at 9:17
  • 1
    \$\begingroup\$ Fail on VROM! \$\endgroup\$
    – l4m2
    Nov 3, 2018 at 10:59
0
\$\begingroup\$

Clojure, 90 bytes

#(do(def a(clojure.string/replace % #"(?ms).*^[Vv]r(o*)m!$.*""$1"))(if(= a %)-1(count a)))

Try it online!

This anonymous function returns the number of "o"s in the vroom string, or -1 if there is no valid vroom string.

Readable version

(fn [s]
  (def a (clojure.string/replace s #"(?ms).*^[Vv]r(o*)m!$.*" "$1"))
  (if (= a s) -1 (count a)))

Explanation

#"(?ms).*^[Vv]r(o*)m!$.*" ; This regex matches any string that contains a valid vroom string. The first capturing group contains only the "o"s in the vroom string
(clojure.string/replace s #"(?ms).*^[Vv]r(o*)m!$.*" "$1") ; Replaces a match of the above regex with its first capturing group. The resulting string is stored in the variable a
(if (= a s) -1 (count a))) ; a equals s if and only if there is no valid vroom string, so if a equal s we return -1. If there is a valid vroom string, a contains only the "o"s from the vroom string, so we return the length of a
\$\endgroup\$
0
\$\begingroup\$

perl -nE, 35 bytes

$s=length$1if/^[Vv]r(o*)m!$/}{say$s

This uses the Eskimo greeting (}{) which abuses the a quick on how the -n option is dealt with by perl.

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

Java 8, 109 bytes

s->{int r=-1;for(var l:s.split("\n"))r=l.matches("[Vv]ro*m\\!")?l.replaceAll("[^o]","").length():r;return r;}

Try it online.

Explanation:

s->{                             // Method with String parameter and integer return-type
  int r=-1;                      //  Result-integer, starting at -1
  for(var l:s.split("\n"))       //  Loop over the lines:
    r=l.matches("[Vv]ro*m\\!")?  //   If the current line matches the regex:
       l.replaceAll("[^o]","").length()
                                 //    Change `r` to the amount of "o"'s in it
      :                          //   Else:
       r;                        //    Leave the result `r` unchanged
  return r;}                     //  Return the result
\$\endgroup\$
0
\$\begingroup\$

C# (.NET Core), 134 122 bytes

for(var a="";a!=null;a=Console.ReadLine())if(new Regex(@"^[Vv]ro*m!$").Match(a).Success)Console.Write(a.Count(x=>x=='o'));

Try it online!

-12 bytes: moved null check into for loop and removed brackets

Ungolfed:

for(var a = ""; a != null; a = Console.ReadLine())  // initialize a, and while a isn't null, set to new line from console
    if(new Regex(@"^[Vv]ro*m!$")                        // set regex
                        .Match(a).Success)              // check if the line from the console matches
        Console.Write(a.Count(x => x == 'o'));              // write the number of 'o's to the console
\$\endgroup\$
5
  • \$\begingroup\$ -10 bytes with C# 6's null-coalescing and conditional operators, also unnecessary {} when using just one statement in the for loop: for(var a="";;a=Console.ReadLine())Console.WriteLine(new Regex(@"^[Vv]ro*m!$").Match(a??"").Success?a.Count(x =>x=='o'):-1); \$\endgroup\$ Nov 2, 2018 at 21:37
  • \$\begingroup\$ Also, this needs using System.Linq; using System.Text.RegularExpressions;, not sure if this is important lol \$\endgroup\$ Nov 2, 2018 at 21:46
  • \$\begingroup\$ The code you provided doesn't actually work, as it will not only output a -1 for every line that it doesn't work on, but it will output -1s forever as there is no check for null. \$\endgroup\$
    – Meerkat
    Nov 5, 2018 at 14:24
  • \$\begingroup\$ No, it won't. a = Console.ReadLine() makes the loop, so each time you're requesting input for the loop to go on, if there is no input, the loop is just waiting, not printing -1 forever \$\endgroup\$ Nov 5, 2018 at 15:28
  • \$\begingroup\$ Proof of concept. Even if it did work as you said, a never-ending loop is not ideal behavior. Regardless, I've moved the null check into the for loop, which removes the brackets (and makes the code shorter than your suggestion). \$\endgroup\$
    – Meerkat
    Nov 5, 2018 at 16:01
0
\$\begingroup\$

05AB1E, 39 37 bytes

|ʒć„VvsåsÁÁD…m!rÅ?s¦¦¦Ù'oså)P}Dgi`'o¢

Although 05AB1E is a golfing languages, regex-based challenges are definitely not its strong suite, since it has no regex-builtins.

Outputs [] if no match was found.

Try it online or verify all test cases.

Explanation:

|              # Get the input split by newlines
 ʒ             # Filter it by:
  ć            #  Head extracted: Pop and push the remainder and head-character
               #   i.e. "vrm!" → "rm!" and "v"
               #   i.e. "Vroaom!" → "roaom!" and "V"
   „Vvså       #  Is this head character in the string "Vv"?
               #   i.e. "v" → 1 (truthy)
               #   i.e. "V" → 1 (truthy)
  s            #  Swap so the remainder is at the top of the stack again
   ÁÁ          #  Rotate it twice to the right
               #   i.e. "rm!" → "m!r"
               #   i.e. "roaom!" → "m!roao"
     D         #  Duplicate it
      …m!rÅ?   #  Does the rotated remainder start with "m!r"?
               #   i.e. "m!r" → 1 (truthy)
               #   i.e. "m!roao" → 1 (truthy)
  s¦¦¦         #  Remove the first three characters from the duplicated rotated remainder
               #   i.e. "m!r" → ""
               #   i.e. "m!roao" → "oao"
      Ù        #  Uniquify, leaving only distinct characters
               #   i.e. "" → ""
               #   i.e. "oao" → "oa"
       'oså   '#  Is this uniquified string in the string "o"?
               #   i.e. "" → 1 (truthy)
               #   i.e. "oa" → 0 (falsey)
  )P           #  Check if all three checks above are truthy
               #   i.e. [1,1,1] → 1 (truthy)
               #   i.e. [1,1,0] → 0 (falsey)
 }             # Close the filter
  D            # After the filter, duplicate the list
   gi          # If its length is 1:
               #   i.e. ["vrm!"] → 1 (truthy)
               #   i.e. [] → 0 (falsey)
     `         #  Push the value in this list to the stack
               #   i.e. ["vrm!"] → "vrm!"
      'o¢     '#  And count the amount of "o" in it (and output implicitly)
               #   i.e. "vrm!" → 0
               # (Implicit else:)
               #  (Implicitly output the duplicated empty list)
               #   i.e. []
\$\endgroup\$
0
\$\begingroup\$

C++, MSVC, 164 159 bytes

-5 bytes thanks to Zacharý

It compiles even with the regex header only

#include<regex>
using namespace std;int f(vector<string>i){smatch m;for(auto&e:i)if(regex_match(e,m,regex("^[Vv]ro*m!$")))return m[0].str().size()-4;return-1;}

Tests :

std::cout << "Vrom!" << " -> " << f({ "Vrom!" }) << '\n';
std::cout << "vrooooooom!" << " -> " << f({ "vrooooooom!" }) << '\n';
std::cout << "Hello, Vroom!" << " -> " << f({ "Hello, Vroom!" }) << '\n';
std::cout << "Foo bar boo baz \\n Vrooom! \\n hi" << " -> " << f({ "Foo bar boo baz", "Vrooom!", "hi" }) << '\n';
std::cout << "Vrm!ooo" << " -> " << f({ "Vrm!ooo" }) << '\n';
std::cout << "PPCG puzzlers pie" << " -> " << f({ "PPCG puzzlers pie" }) << '\n';
std::cout << "hallo \\n vROOOm!" << " -> " << f({ "hallo", "vROOOm!" }) << '\n';
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I think using namespace std; would save a few bytes \$\endgroup\$
    – Adalynn
    Nov 5, 2018 at 14:30

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.

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