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 code-golf, so the shortest answer in bytes wins.
- Standard code-golf loopholes apply. Cheating is prohibited.
- Other boolean return values, such as
1and0, 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.
-
1\$\begingroup\$ Will the haiku-w always contain 3 lines? \$\endgroup\$user41805– user418052017年01月29日 10:31:54 +00:00Commented Jan 29, 2017 at 10:31
-
1\$\begingroup\$ Yes. If the input contains more than or fewer than 3 lines, the program should return false. \$\endgroup\$DomTheDeveloper– DomTheDeveloper2017年01月29日 10:33:54 +00:00Commented Jan 29, 2017 at 10:33
-
6\$\begingroup\$ Will there ever be leading or trailing spaces on any line? Or multiple spaces separating words? \$\endgroup\$Greg Martin– Greg Martin2017年01月29日 10:34:38 +00:00Commented Jan 29, 2017 at 10:34
-
9\$\begingroup\$ By the way, clarifications like this are a primary reason to post proposed questions in the Sandbox first. :) \$\endgroup\$Greg Martin– Greg Martin2017年01月29日 10:43:26 +00:00Commented Jan 29, 2017 at 10:43
-
12\$\begingroup\$ Bonus points for submissions where the code itself is a haiku-w. \$\endgroup\$Glorfindel– Glorfindel2017年01月30日 07:22:54 +00:00Commented Jan 30, 2017 at 7:22
44 Answers 44
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.
-
1\$\begingroup\$
%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-...). \$\endgroup\$Neil– Neil2017年01月29日 10:29:44 +00:00Commented Jan 29, 2017 at 10:29 -
\$\begingroup\$ Thanks for the tip about the parentheses. Also, I changed my approach, so I don't explicitly check for length anymore. \$\endgroup\$Luke– Luke2017年01月29日 10:46:36 +00:00Commented Jan 29, 2017 at 10:46
-
1\$\begingroup\$ Ah, in that case, don't bother with the calculation, just use
a=>a.map(c=>c.split.length)=='5,7,5'. \$\endgroup\$Neil– Neil2017年01月29日 10:55:56 +00:00Commented Jan 29, 2017 at 10:55 -
\$\begingroup\$ Hehe, you're right. I should've thought of that... \$\endgroup\$Luke– Luke2017年01月29日 10:56:37 +00:00Commented Jan 29, 2017 at 10:56
-
\$\begingroup\$ You still don't need the
+''-==stringifies if the other argument is a string. \$\endgroup\$Neil– Neil2017年01月29日 11:13:17 +00:00Commented Jan 29, 2017 at 11:13
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
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
-
2\$\begingroup\$ This fails if the input consists of one line containing 575 words, or two lines containing 57 and 5 words, etc. \$\endgroup\$lynn– lynn2017年01月29日 12:51:40 +00:00Commented Jan 29, 2017 at 12:51
-
\$\begingroup\$ @Lynn, true, putting on hold, until this is fixed. \$\endgroup\$zeppelin– zeppelin2017年01月29日 13:09:04 +00:00Commented Jan 29, 2017 at 13:09
-
\$\begingroup\$ @Lynn, should be fixed now \$\endgroup\$zeppelin– zeppelin2017年01月29日 15:47:36 +00:00Commented Jan 29, 2017 at 15:47
-
1\$\begingroup\$ Very clever fix! :) \$\endgroup\$lynn– lynn2017年01月29日 15:55:33 +00:00Commented Jan 29, 2017 at 15:55
Python, 42 bytes
lambda l:[s.count(' ')for s in l]==[4,6,4]
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.
-
\$\begingroup\$ If you're okay with supporting only Python 2, you can save two bytes:
map(str.count,l,' '). \$\endgroup\$vaultah– vaultah2017年01月31日 17:07:48 +00:00Commented Jan 31, 2017 at 17:07
Jelly, (削除) 10 (削除ここまで) 9 bytes
ċ6ドル="\©\‘
Explanation
ċ6ドル="\©\‘ Input: length-3 list of strings
€ For each string
ċ 6 Count the number of spaces
"\©\‘ Convert string to code page indices, makes [4, 6, 4]
= Match
-
\$\begingroup\$ Also
ċ6ドル=4,6,4andċ6ドル=464D¤... I can’t find anything shorter, though. (Oh, you can flip it, too:464D=ċ6ドル$) \$\endgroup\$lynn– lynn2017年01月29日 13:01:27 +00:00Commented Jan 29, 2017 at 13:01 -
\$\begingroup\$
ċ6ドルḌ=464works fine for 8. \$\endgroup\$Jonathan Allan– Jonathan Allan2017年01月29日 13:42:48 +00:00Commented Jan 29, 2017 at 13:42 -
\$\begingroup\$ Actually, no it does not, sorry. \$\endgroup\$Jonathan Allan– Jonathan Allan2017年01月29日 13:58:58 +00:00Commented Jan 29, 2017 at 13:58
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.
-
1\$\begingroup\$ ......well crap \$\endgroup\$tbodt– tbodt2017年01月29日 11:40:48 +00:00Commented Jan 29, 2017 at 11:40
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.
Retina, 12 bytes
M%`
^4¶6¶4$
(there's a trailing space after the first line)
M%`- Count the number of spaces in each line.M- Match mode - print the number of matches.%- for each line`- separate configuration and regex pattern- - just a space.
^4¶6¶4$- There should be 4, 6, and 4 spaces, and exactly three lines.¶matches newlines. The rest is a simple regular expression.
Prints 1 for valid input, 0 for invalid.
Haskell, (削除) 34 (削除ここまで) 33 bytes
f l=[sum[1|' '<-c]|c<-l]==[4,6,4]
Edit: thanks to @xnor for a byte!
-
\$\begingroup\$ Pointful is shorter:
f l=[sum[1|' '<-c]|c<-l]==[4,6,4]. \$\endgroup\$xnor– xnor2017年01月29日 22:40:06 +00:00Commented Jan 29, 2017 at 22:40
PowerShell, 43 bytes
"$args"-replace'\S'-match'^( )
1円
1円$'
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.
-
1\$\begingroup\$ That is an interesting aproach! \$\endgroup\$Ismael Miguel– Ismael Miguel2017年01月31日 09:28:47 +00:00Commented Jan 31, 2017 at 9:28
Python, (削除) 58 (削除ここまで) 44 bytes
lambda h:[len(l.split())for l in h]==[5,7,5]
-14 by tbodt
-
\$\begingroup\$ You're allowed to take the input as a length 3 list of strings. You can save the bytes spent using
split("\n"). \$\endgroup\$miles– miles2017年01月29日 10:58:28 +00:00Commented Jan 29, 2017 at 10:58 -
\$\begingroup\$ 44 bytes:
lambda h:[len(l.split())for l in h]==[5,7,5]\$\endgroup\$tbodt– tbodt2017年01月29日 11:40:25 +00:00Commented Jan 29, 2017 at 11:40 -
\$\begingroup\$ Someone make this shorter to reach crossed out 44 \$\endgroup\$Charlie– Charlie2017年02月02日 20:56:53 +00:00Commented Feb 2, 2017 at 20:56
Pyth, 9 bytes
qj464T/R;
A program that takes input of a list of "quoted strings" and prints True or False as appropriate.
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
Pyke, (削除) 11 (削除ここまで) 9 bytes
dL/uq
dL/ - map(i.count(" "), input)
q - ^ == V
u - [4, 6, 4]
After the u byte there are the following bytes: 0x03 0x04 0x06 0x04
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 (#).
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))
-
\$\begingroup\$ First time I've ever seen
elbefore, thanks for that. \$\endgroup\$BLT– BLT2017年01月30日 05:48:31 +00:00Commented Jan 30, 2017 at 5:48
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 0.
A positive testcase:
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;
}
-
4\$\begingroup\$ 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. \$\endgroup\$ETHproductions– ETHproductions2017年01月29日 23:16:35 +00:00Commented Jan 29, 2017 at 23:16
Ruby 1.9.3
Not golfed, but is itself a haiku-w
def haiku_w(input)
lines = input.split("\n")
lengths = lines.map(&:split).map(&:length)
lengths.eql?([5,7,5])
end
or...
lines equals input split (newlines)
lengths equals lines map split map length
lengths equals five seven five?
Unfortunately doesn't work with leading whitespace on any lines, but does cope with trailing.
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 ')
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.
-
4
-
\$\begingroup\$ I'll give you that @Dada. That is one serious test case :) \$\endgroup\$ElPedro– ElPedro2017年01月29日 14:49:00 +00:00Commented Jan 29, 2017 at 14:49
-
\$\begingroup\$ Corrected and tested with your test case. \$\endgroup\$ElPedro– ElPedro2017年01月29日 14:53:58 +00:00Commented Jan 29, 2017 at 14:53
MATL, 16 bytes
"@Y:Ybn&h][ACA]=
The input is a cell array of strings and returns a truthy or falsey array.
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
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.
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. :)
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:
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);
}
}
SimpleTemplate, 77 bytes
Sadly, the regular expression aproach is the shortest.
{@if"@^([^\s]+ ?){5}\s([^\s]+ ?){7}\s([^\s]+ ?){5}+$@"is matchesargv}{@echo1}
Requires that the text is given as the first argument, with *NIX-style newlines. This won't work with Windows-style newlines.
Ungolfed:
{@if "@^([^\s]+ ?){5}\s([^\s]+ ?){7}\s([^\s]+ ?){5}+$@"is matches argv}
{@echo 1}
{@/}
Non-regex based, 114 byes
{@setR 1}{@eachargv asL keyK}{@php$DATA[L]=count(explode(' ',$DATA[L]))!=5+2*($DATA[K]&1)}{@set*R R,L}{@/}{@echoR}
This requires that each line is given as an argument to the function.
Ungolfed:
{@set result 1}
{@each argv as line key k}
{@php $DATA['line'] = count(explode(' ', $DATA['line'])) != 5+2*( $DATA['k'] & 1 )}
{@set* result result, line}
{@/}
{@echo result}
Stacked, 22 bytes
[' 'eq sum]map(4 6 4)=
Takes input from the top of the stack as a list of character strings, as such:
($'The man in the suit' $'is the same man from the store.' $'He is a cool guy.')
Explanation
[' 'eq sum]map(4 6 4)=
[ ]map map the following function over each item
' 'eq vectorized equality with ' '
sum summed
(4 6 4)= is equal to (4 6 4)
05AB1E, 9 bytes
€#€g575SQ
Explanation
€# # split each line on spaces
€g # get length of each line
575 # push the number 575
S # split into list of digits
Q # compare for equality
-
\$\begingroup\$ I couldn't get away from
vyand 10 bytes, nice solution. Usingð¢and464instead was my approach, unfortunately 464 is still 2 bytes compressed, obviously. \$\endgroup\$Magic Octopus Urn– Magic Octopus Urn2017年01月31日 19:41:26 +00:00Commented Jan 31, 2017 at 19:41 -
\$\begingroup\$ @carusocomputing: That's an interesting idea. I think you could post that as
ð¢464SïQin 2sable for 8 bytes. \$\endgroup\$Emigna– Emigna2017年01月31日 20:41:07 +00:00Commented Jan 31, 2017 at 20:41 -
\$\begingroup\$ You go ahead, that's more your answer than mine in all honesty (I think it's a winning answer too!) \$\endgroup\$Magic Octopus Urn– Magic Octopus Urn2017年01月31日 21:03:46 +00:00Commented Jan 31, 2017 at 21:03
-
\$\begingroup\$ @carusocomputing:
ð¢is the main part of that answer and it was your idea :) \$\endgroup\$Emigna– Emigna2017年01月31日 21:20:07 +00:00Commented Jan 31, 2017 at 21:20 -
\$\begingroup\$ ahhh, just give me a shoutout. If it ends up having a flaw I won't know how to fix it haha. \$\endgroup\$Magic Octopus Urn– Magic Octopus Urn2017年01月31日 21:24:47 +00:00Commented Jan 31, 2017 at 21:24
Java (OpenJDK), 82 bytes
-2 bytes thanks to @corvus_192!
s->s[0].split(" ").length==5&s[2].split(" ").length==5&s[1].split(" ").length==7
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.
-
\$\begingroup\$ What if you have only two lines as input, or four? \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2017年01月30日 10:30:10 +00:00Commented Jan 30, 2017 at 10:30
-
\$\begingroup\$ @KevinCruijssen according the op, "A length-3 list of strings as an input is also acceptable". My program takes a length-3 list of lines. \$\endgroup\$Pavel– Pavel2017年01月30日 17:40:20 +00:00Commented Jan 30, 2017 at 17:40
-
\$\begingroup\$ You could get a map function if you called
Arrays.stream, but that's long enough that it may not be worth using (especially if you need to importArrays) \$\endgroup\$Pokechu22– Pokechu222017年01月30日 18:11:34 +00:00Commented Jan 30, 2017 at 18:11 -
\$\begingroup\$ @Pokechu22 yeah I tried that, still ended up being longer. \$\endgroup\$Pavel– Pavel2017年01月30日 21:18:25 +00:00Commented Jan 30, 2017 at 21:18
-
\$\begingroup\$ You can use
&instead of&&to save two bytes \$\endgroup\$corvus_192– corvus_1922017年01月31日 09:53:21 +00:00Commented Jan 31, 2017 at 9:53
SmileBASIC, (削除) 96 (削除ここまで) 94 bytes
INPUT A,ドルB,ドルC$?C(A,4ドル)*C(B,6ドル)*C(C,4ドル)DEF C(S,E)WHILE""<S
INC N,POP(S)<"!
WEND
RETURN N==E
END