Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

A haiku is a poem with three lines, with a 5/7/5 syllable count, respectively.

A haiku-w is poem with three lines, with a 5/7/5 word count, respectively.

Challenge

Write a program that will return true if the input is a haiku-w, and false if not.

A valid haiku-w input must consist of 3 lines, separated by a newline.

  • Line 1 must consist of 5 words, each word separated by a space.
  • Line 2 must consist of 7 words, each word separated by a space.
  • Line 3 must consist of 5 words, each word separated by a space.

Examples

The man in the suit
is the same man from the store.
He is a cool guy.

Result: True

Whitecaps on the bay:
A broken signboard banging
In the April wind.

Result: False


Rules

  • This is , so the shortest answer in bytes wins.
  • Standard code-golf loopholes apply. Cheating is prohibited.
  • Other boolean return values, such as 1 and 0, are acceptable.
  • A length-3 list of strings as an input is also acceptable.
  • Valid haiku-w inputs should not have leading or trailing spaces, or multiple spaces separating words.
share|improve this question
1  
Will the haiku-w always contain 3 lines? – Kritixi Lithos yesterday
1  
Yes. If the input contains more than or fewer than 3 lines, the program should return false. – DomTheDeveloper yesterday
5  
Will there ever be leading or trailing spaces on any line? Or multiple spaces separating words? – Greg Martin yesterday
1  
Good question. Valid haiku-w inputs should not have leading or trailing spaces, or multiple spaces separating words. – DomTheDeveloper yesterday
8  
By the way, clarifications like this are a primary reason to post proposed questions in the Sandbox first. :) – Greg Martin yesterday

27 Answers 27

JavaScript (ES6), 73 72 64 63 54 42 39 bytes

Thanks to Neil for saving 13 bytes

a=>a.map(b=>b.split` `.length)=='5,7,5'

Explanation

This is a fat-arrow function that takes an array of strings as argument. It replaces each line by its word count. If it is a haiku-w, a now contains an array of a five, a seven and a five again. Since JavaScript doesn't allow us to compare 2 arrays at the same time, the array is converted to a string first, and then compared. This results in a boolean that is returned.

share|improve this answer
1  
% and * have the same precedence, so you don't need the ()s, although I think (d*2|5) might also work. Also you can get away with a single &, although I think you can improve on even that by using (b...).length==3>b.some(...length-...). – Neil yesterday
    
Thanks for the tip about the parentheses. Also, I changed my approach, so I don't explicitly check for length anymore. – Luke yesterday
1  
Ah, in that case, don't bother with the calculation, just use a=>a.map(c=>c.split .length)=='5,7,5'. – Neil yesterday
    
Hehe, you're right. I should've thought of that... – Luke yesterday
    
You still don't need the +'' - == stringifies if the other argument is a string. – Neil yesterday

Mathematica, 21 bytes

{4,6,4}==Count@" "/@#&

Unnamed function taking a list of lists of characters as input and returning True or False. Simply counts how many spaces are in each list of characters, which under the rules of the challenge correlate perfectly with the number of words in each line.

Previous submission:

Mathematica, 31 bytes

Length/@StringSplit/@#=={5,7,5}&

Unnamed function taking a list of strings as input and returning True or False.

share|improve this answer

Jelly, 10 9 bytes

ċ€⁶⁼“¥©¥‘

Try it online!

Explanation

ċ€⁶⁼“¥©¥‘  Input: length-3 list of strings
 €         For each string
ċ ⁶          Count the number of spaces
    “¥©¥‘  Convert string to code page indices, makes [4, 6, 4]
   ⁼       Match
share|improve this answer
    
Also ċ€⁶⁼4,6,4 and ċ€⁶⁼464D¤… I can’t find anything shorter, though. (Oh, you can flip it, too: 464D⁼ċ€⁶$) – Lynn 22 hours ago
    
ċ€⁶Ḍ=464 works fine for 8. – Jonathan Allan 22 hours ago
    
Actually, no it does not, sorry. – Jonathan Allan 21 hours ago

Python, 42 bytes

lambda l:[s.count(' ')for s in l]==[4,6,4]

Try it online!

Takes input as a list of lines, with the words separated by single spaces.

As we're guaranteed there'll be no leading or trailing spaces, and only single spaces will seperate each word, we can verify a w-haiku by simply counting the spaces in each line.

We do this in a list comprehension, to create a list of the space-counts. If it is a correct haiku, it should look like [4, 6, 4], so we compare it with this and return the result.

share|improve this answer

Batch, 102 bytes

@echo off
call:c&&call:c 2||exit/b
:c
set/an=%1+5
set/ps=
for %%W in (%s%)do set/an-=1
exit/b%n%

Exits with non-zero errorlevel as soon as it reads a line with the wrong number of words.

share|improve this answer
    
......well crap – tbodt yesterday

Perl, 26 bytes

24 bytes of code + 2 bytes for -ap flags.

$m.=@F}{$_=$m==575&$.==3

Try it online!

share|improve this answer

Haskell, 34 33 bytes

f l=[sum[1|' '<-c]|c<-l]==[4,6,4]

Try it online!.

Edit: thanks to @xnor for a byte!

share|improve this answer
    
Pointful is shorter: f l=[sum[1|' '<-c]|c<-l]==[4,6,4]. – xnor 13 hours ago

AWK (GNU Awk), 24, 30, 28, 20 bytes

Golfed

517253==$0=q=q NF NR

Will output "517253" for True, and empty string for False.

In awk, any nonzero numeric value or any nonempty string value is true. Any other value (zero or the null string, "") is false

The GNU Awk User's Guide

How It Works

Each awk statement (rule) consists of a pattern (or expression) with an associated action:

pattern {action}

Awk will read the input line by line (record by record) and evaluate pattern expression to see if a corresponding action is to be invoked.

The code above is a standalone Awk expression (pattern) w/o the action block, which is implied to be {print $0} in that case.

It should be read right-to-left:

q=q NF NR

Append a Number of Fields (words) and Number of Records (i.e. the current line number), to the variable q.

This way, when processing a proper Haiku-w, q will be set to:

  • 51 - on line #1 (5 words)
  • 5172 - on line #2 (5 words + 7 words)
  • 517253 - on line #3 (5 words + 7 words + 5 words)

$0=q

Assign the newly computed value of q to $0 (which holds the whole current line/record by default).

517253==$0

Compare it with a "signature" for a proper Haiku-w (517253), if there is a match, the whole expression evaluates to "true" and a corresponding action (implicit print $0) is run, sending "517253" to stdout (True), otherwise output will be empty (False).

Note that this will properly recognize a Haiku-w, even if it is followed by an arbitrary number of garbage lines, but I believe that is ok, as:

A length-3 list of strings as an input is also acceptable.

(i.e. we can assume the input to be 3 lines long)

Test

>awk '517253==$0=q=q NF NR'<<EOF
The man in the suit
is the same man from the store.
He is a cool guy.
EOF

517253

Try It Online !

share|improve this answer
1  
This fails if the input consists of one line containing 575 words, or two lines containing 57 and 5 words, etc. – Lynn 22 hours ago
    
@Lynn, true, putting on hold, until this is fixed. – zeppelin 22 hours ago
    
@Lynn, should be fixed now – zeppelin 19 hours ago
    
Very clever fix! :) – Lynn 19 hours ago

Python, 58 44 bytes

lambda h:[len(l.split())for l in h]==[5,7,5]

-14 by tbodt

share|improve this answer
    
You're allowed to take the input as a length 3 list of strings. You can save the bytes spent using split("\n"). – miles yesterday
    
44 bytes: lambda h:[len(l.split())for l in h]==[5,7,5] – tbodt yesterday

Retina, 12 bytes

M%` 
^4¶6¶4$

(there's a trailing space after the first line)

Try it online!

  • M%`  - Count the number of spaces in each line.
  • ^4¶6¶4$ - There should be 4, 6, and 4 spaces, and exactly three lines.

Prints 1 for valid input, 0 for invalid.

share|improve this answer

C 142 bytes

void f(){char *c;l=3;s[3]={0};while(l>0){if(*c==' ')s[l-1]++;if((*c=getchar())=='\n'){l--;}}printf("%d",(s[0]==4 && s[1]==6 && s[2]==4)?1:0);}

Ungolfed version:

void f()
{
  char *c;
  c = (char *)malloc(sizeof(char)); 
  int l=3;
  int s[3]= {0};


 while(l>0)
 {  
   if(*c==' ')
   s[l-1]++;

   if( (*c=getchar())=='\n')
   {    
     l--;        
   }   
 }
printf("%d",(s[0]==4 && s[1]==6 && s[2]==4)?1:0);

}

Returns 1 for 5/7/5 sequence else 1.

A positive testcase:

enter image description here

share|improve this answer

Pyth, 9 bytes

qj464T/R;

A program that takes input of a list of "quoted strings" and prints True or False as appropriate.

Test suite

How it works

qj464T/R;   Program. Input: Q
qj464T/R;Q  Implicit variable fill
     T      Are the base-10
 j          digits
  464       of 464
q           equal
      /     to the number
        ;   of spaces
       R    in each string
         Q  in the input?
            Implicitly print
share|improve this answer

Pyke, 11 9 bytes

dL/uq

Try it here!

dL/       -  map(i.count(" "), input)
        q - ^ == V
   u  -  [4, 6, 4]

After the u byte there are the following bytes: 0x03 0x04 0x06 0x04

share|improve this answer
    
You appear to have unprintable characters in this answer. Can you give a hexdump? – isaacg 5 hours ago
    
@isaacg added which bytes they are. I'll add a proper hexdump when I'm at a computer – muddyfish 3 hours ago

Python 2, 57 64 bytes

Edit Corrected with the addition of 7 bytes after feedback from @Dada. Thanks!

i,j=input,''
for x in i():j+=`len(x.split())`+' '
i(j=='5 7 5 ')

Try it online!

Not the shortest Python answer by a long way but just wanted to use the new trick I learned recently of using input() to display the output and save a print statement. Takes a list of lines as input. Requires Ctrl C (or any other key-press for that matter) to terminate the program (with an exception) in a terminal but works fine without on TIO.

share|improve this answer
4  
This will fail in cases like this one. – Dada 20 hours ago
    
I'll give you that @Dada. That is one serious test case :) – ElPedro 20 hours ago
    
Corrected and tested with your test case. – ElPedro 20 hours ago

MATL, 16 bytes

"@Y:Ybn&h][ACA]=

The input is a cell array of strings and returns a truthy or falsey array.

Try it Online

Explanation

        % Implicitly grab input
"       % For each element in the cell array
@Y:Yb   % Split it on spaces
n       % Count the number of elements
&h      % Horizontally concatenate everything on the stack
[ACA]   % Create the array [5 7 5]
=       % Perform an element-wise equality
        % Implicitly display the truthy/falsey array
share|improve this answer

MATLAB / Octave, 38 bytes

@(x)cellfun(@(y)sum(y==32),x)==[4 6 4]

This solution accepts a cell array of strings as input, counts the number of spaces in each line and then compares the result to the array [4 6 4] and yields a truthy (all values are 1) or falsey (any value is zero) array.

Online demo

share|improve this answer

Perl 6, 25 bytes

{.lines».words~~(5,7,5)}
share|improve this answer

J, 12 bytes

4 6 4=#@;:@>

The input is a boxed list of strings.

Explanation

This is a fork with a constant left tine. This checks the result of the right tine, #@;:@>, for equality with 4 6 4. The right time unboxes each (>), then (@) converts each string to words (;:), then (@) takes the length of each (#).

share|improve this answer

Java (OpenJDK), 82 bytes

s->s[0].split(" ").length==5&&s[2].split(" ").length==5&&s[1].split(" ").length==7

Try it online!

It looks so golfable but without a builtin map function, I can't find a good way. Iterating through the array is a few bytes longer, as is writing a map function using streams.

Lambda expression takes an array of Strings and returns a Boolean.

share|improve this answer
    
What if you have only two lines as input, or four? – Kevin Cruijssen 1 hour ago

C++ 357 bytes

Sort of new to code golf, but this is the best I could do quickly

#include <iostream>
using namespace std;
int n(std::string s)
{
    int b = 0;
    for(char c: s)
        if(c == ' ') b++;
    cout << "C = " << b;
    return b;
}
int main()
{
    string a, b, c;
    getline(cin, a);
    getline(cin, b);
    getline(cin, c);
    if(n(a)==4 && n(b)==6 && n(c)==4)
        cout<<'1';
    else cout << '0';
    return 0;
}
share|improve this answer
1  
Welcome to PPCG! The goal of code golf is to make your code as short as possible; a good first step would be to remove all unnecessary whitespace. – ETHproductions 12 hours ago

R, 48 bytes

all(stringr::str_count(scan(,"")," ")==c(4,6,4))

Reads a 3-length character vector from stdin and works by counting the number of spaces. To count the number of spaces we use the str_count from the stringr package which can count occurrences based on a regex pattern.

An alternative approach without using packages could be:

all(sapply(scan(,""),function(x)length(el(strsplit(x," "))))==c(5,7,5))
share|improve this answer
    
First time I've ever seen el before, thanks for that. – BLT 5 hours ago

Japt, 11 bytes

Saved lots of bytes thanks to @ETHproductions

This takes an array of three strings as input.

®¸lÃ¥"5,7,5

Run it online!

share|improve this answer

PowerShell, 43 bytes

"$args"-replace'\S'-match'^(    )
\1  
\1$'

Try it online!

Explanation

Takes input as a newline separated string.

Removes all non-whitespace, then checks to see that it matches "4 spaces, newline, 6 spaces, newline, 4 spaces newline" exactly, using a regex.

The capture group matches 4 spaces, the backreference \1 refers to that. Newlines are embedded in the string. Note the second line of the regex contains two spaces after the backreference.

share|improve this answer

Clojure, 44 bytes

#(=(for[l %](count(filter #{\ }l)))'(4 6 4))

Input is list of strings. Function finds only spaces and counts them. This explanation is a Haiku. :)

share|improve this answer

SmileBASIC, 96 bytes

INPUT A$,B$,C$?C(A$,4)*C(B$,6)*C(C$,4)DEF C(S,E)WHILE LEN(S)INC N,POP(S)<"!
WEND
RETURN N==E
END
share|improve this answer

R, 100 bytes

f<-function(a){all(sapply(a,function(x){length(grep(" ",as.list(strsplit(x,"")[[1]])))})==c(4,6,4))}

Takes as an argument a length-3 list of strings. Probably won't be golfed further since further golfing turns it into @Billywob's answer.

share|improve this answer

Java 7, 154 bytes

class M{public static void main(String[]a){System.out.print(a.length==3&&a[0].split(" ").length==5&a[1].split(" ").length==7&a[2].split(" ").length==5);}}

The program requirement and potential of having less or more than three lines, not too mention Java's verbosity itself, causes this 'golfed' code to be pretty big..

Ungolfed:

Try it here.

class M{
  public static void main(String[] a){
    System.out.print(a.length == 3
        && a[0].split(" ").length == 5
         & a[1].split(" ").length == 7
         & a[2].split(" ").length == 5);
  }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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