# Is it a digit haiku?

We can read 13576870234289 digit-by-digit in English, and it makes a haiku:

one three five seven
six eight seven zero two
three four two eight nine

We say it's a "digit haiku", because when read out like this, it's 5+7+5 syllables long, and no word is broken across a line.

For example, 111171111101111 is not a digit haiku, even though it has 17 syllables:

one one one one se-
-ven one one one one one ze-
-ro one one one one

Two-syllable digits (0 "zero" and 7 "seven") are not allowed to span the 5th-and-6th syllable positions, or the 12th-and-13th syllable positions. (Other than that, any 17-syllable digit string makes a digit haiku.)

All other digits beside 0 and 7 are one syllable long in English.

Given a non-empty string of digits (or list of numbers) 0 through 9, decide whether it forms a digit haiku.

• You can assume the string does not start with 0, and thus you're also permitted to take input as a number.

• You can assume the input is at most 17 digits long. However, it may be more than 17 syllables.

• This is : aim to write the shortest answer, measured in bytes.

## Test cases

7767677677 -> True
13576870234289 -> True
123456789012345 -> True
11111111111111111 -> True
9 -> False
9876543210 -> False
11171111101111 -> False
111171111101111 -> False
998765432101234 -> False
77777777777777777 -> False

• Nice challenge! It's missing a scoring system though, rip. This is code-golf, I'm assuming? Oct 20, 2020 at 1:42
• I'm not familiar with English speaking. So, how many syllables each digits contains?
– tsh
Oct 20, 2020 at 2:16
• @tsh All the one-digit numbers have one syllable, except 0 and 7 have two.
– xnor
Oct 20, 2020 at 2:17
• Suggested test cases: 1111111111111117 and 11111111111111171 Oct 20, 2020 at 4:21
• It'd be a horrible code-golf entry, but Mathematica actually has builtins to "help" with this—for example, Flatten[#~WordData~"Hyphenation"&/@IntegerName@IntegerDigits@#] & yields {"one", "three", "five", "sev", "en", "six", "eight", "sev", "en", "ze", "ro", "two", "three", "four", "two", "eight", "nine"}. Oct 22, 2020 at 22:46

# Retina 0.8.2, 25 bytes

0|7
_#
^.{5}\w.{6}\w.{4}$ Try it online! Link includes test cases. Explanation: 0|7 _#  Expand 0 and 7 into two syllables. ^.{5}\w.{6}\w.{4}$


Check that neither the 6th nor the 13th syllable is the second such syllable.

# JavaScript (ES6),  48  41 bytes

Expects a list of digits. Returns a Boolean value.

a=>a.map(d=>i-=d%7?1:i%7-6?2:.1,i=17)&&!i


Try it online!

### How?

We use a syllable counter $$\i\$$ initialized to $$\17\$$, subtract either $$\1\$$ or $$\2\$$ from $$\i\$$ after each digit and check whether we end up with $$\i=0\$$. The haiku is supposed to look like that:

17 16 15 14 13
12 11 10 09 08 07 06
05 04 03 02 01

When the digit is either $$\0\$$ or $$\7\$$ and $$\i\equiv 6\pmod 7\$$, we have an invalid hyphenation and subtract $$\1/10\$$ from $$\i\$$ instead of $$\2\$$. Because this test can only be triggered once, $$\i\$$ remains a non-integer value whatever happens next.

# J, 32 30 bytes

4=5 12 17+/@e.~[:+/\0,~1+0=7|]


-2 thanks to xash

Try it online!

## original explanation

[:(5&e.*12&e.*17={:)[:+/\1+0=7|]


Try it online!

Straightforward:

• Take list of digits
• 7|] mod 7
• 0= equals 0 (returns 1-0 list)
• 1+ add 1 (now list of 1-2)
• [:+/\ scan sum
• [:(5&e.*12&e.*17={:) is 5 an elm and is 12 an elm and is 17 the last?
• A port to oK is possible with 31 bytes. Oct 26, 2020 at 21:05
• Feel free to post that if you'd like. Oct 26, 2020 at 21:39
• 30b by appending a dummy 0 and thus getting two 17s in the valid case.
– xash
Oct 27, 2020 at 0:56
• @xash very nice, ty Oct 27, 2020 at 1:24

# Jelly, 11 bytes

7ḍ‘ŒṖ§Ḍ575e


Try it online!

# Explanation

7ḍ‘ŒṖ§Ḍ575e  Main Link
// convert to syllables
7ḍ           Divisibility by 7 (1 for 0 and 7, 0 otherwise)
‘          Increment (2 for 0 and 7, 1 otherwise; this gives the syllables)
// all ways to divide the digits into lines, and total syllable counts
ŒṖ        Partitions (all divisions of a list)
§       Sum each sublist for each partition
// check if any of them are [5, 7, 5]
Ḍ      Convert the lines' syllable sizes into a decimal integer; this can cause collisions but not if the total number of syllables is maximum 34
575e  Is 5-7-5 a possible partition?


Takes a long time on some test cases so I didn't include them.

-1 byte thanks to Jonathan Allan

• @JonathanAllan Ah, guess I need to review what vectorization to a depth actually means. Thanks! Oct 20, 2020 at 13:14

# JavaScript (Node.js), 46 bytes

s=>/^.{9},.{13},.{9}$/.test(s.map(c=>c%7||.1))  Try it online! Take input as array of digits. Output truthy vs. falsy. • s.map(c=>c%7||.1) mapping each digits to a number. Digits 0 or 7 which has 2 syllables are mapped into 0.1 while others are mapped into an 1 digit number. • RegExp.prototype.test converts its parameter into string. The mapping result is an array. When try to convert array into a string, each elements are converted into string and connected by a comma (,). So, basically, each digits in the string is 1 syllable. And commas between theme mean you can break line here, while dots mean you cannot break line here. • Finally, /^.{9},.{13},.{9}$/ test if the string has a 5-7-5 syllables pattern.
• looks more like strange magic than javascript. How does it work? Oct 22, 2020 at 13:02

# Python 2, 53 bytes

t=17
for d in input():t-=0<d%7or 2+t%7/6*t
print t==0


Try it online!

Based on Arnauld's solution. I use True/False output here and in the answers below since I'm not sure what output is allowed.

55 bytes

t=4
for d in input():t-=1+~d%7/6+t%47/46*40
print-t==93


Try it online!

58 bytes

t=1
for d in input():t=t<<1+~d%7/6|1
print-3967&t>>5==4225


Try it online!

58 bytes

s=t=0
for d in input():s+=1+~d%7/6;t+=s%7==5
print s*t==34


Try it online!

• -3 bytes if you input as numbers and use (mod 7) to check the numbers Oct 20, 2020 at 2:05
• @HyperNeutrino Thanks, I had missed that a list of digits was allowed. This might allow further improvements.
– xnor
Oct 20, 2020 at 2:07
• I'm always conflicted about this output case: returning a truthy/falsey value from a function feels OK, but when printing from a full-program, it's like the value "leaves the Python world and becomes a string in the OS world", where Python's concept of truthy/falsey doesn't exist anymore. So, for full programs, I think "two constant distinguishing outputs" makes more sense. But deciding by exit code is fine too, so maybe you can finish with t/0.
– Lynn
Oct 20, 2020 at 11:38

# R, 726665 63 bytes

Edit: -6 bytes thanks to Robin Ryder, and -2 bytes thanks to Giuseppe

max(s<-cumsum(1+!utf8ToInt(scan(,''))%%7-6))==17&5%in%s&12%in%s


Try it online!

• 66 bytes by using only cumsum and avoiding those cs. Oct 20, 2020 at 12:44
• Thanks! I kind-of had in mind to use the -48...%%7 trick but you beat me to it! The double %in% is also nice (and I'd never have guessed it'd be shorter than c). Oct 20, 2020 at 13:49
• Well, it also allows you to get rid of the all, which is why it comes out shorter! Oct 20, 2020 at 14:50
• 63 bytes Oct 21, 2020 at 18:06
• Thanks @Giuseppe! That's really clever. Oct 21, 2020 at 20:40

# C (gcc), 96 $$\\cdots\$$ 92 91 bytes

Added 14 bytes to fix a bug kindly pointed out by HyperNeutrino.
Saved 2 bytes thanks to rtpax!!!
Saved a byte thanks to ceilingcat!!!

p;h;s;c;f(long n){for(h=5,p=s=c=0;n;c=c/h?p|=c!=h,h^=2,!++s:c,n/=10)c+=n%10%7?1:2;h=p|s<3;}


Try it online!

Returns $$\0\$$ if the input integer is a digit haiku or $$\1\$$ otherwise.

• 93 bytes Oct 20, 2020 at 17:05
• @rtpax Nice one - thanks! :-) Oct 20, 2020 at 18:47
• @ceilingcat Sweet, also spotted c/h instead of c>=h - thanks! :D Oct 24, 2020 at 11:39

# Charcoal, 25 bytes

≔⭆Ｓ∨﹪Ｉι⁷χθ›⁼¹⁷Ｌθ№﹪⌕Ａθ0⁷¦⁵


Try it online! Link is to verbose version of code. Outputs a Charcoal boolean i.e. - for haiku, nothing if not. Works like my Retina answer, except it replaces 0 and 7 with 10 and checks that neither the 6th nor the 13th syllable is 0. Explanation:

≔⭆Ｓ∨﹪Ｉι⁷χθ


Reduce all of the digits modulo 7, then change all 0s to 10, so that 0 represents a second syllable.

›⁼¹⁷Ｌθ


Check that there are 17 syllables, but not that...

№﹪⌕Ａθ0⁷¦⁵


any second syllables are at position equivalent to 5 (modulo 7).

• I don't think this works for cases like 9 where there aren't enough characters? Oct 20, 2020 at 0:39
• @FryAmTheEggman Whoops, totally forgot to include that check. Fixed now.
– Neil
Oct 20, 2020 at 9:47

# Perl 5 (-p), 38, 34 bytes

s/0|7/ /g;$_=/^.{5}\V.{5}\H.{5}$/


Try it online!

# PowerShell Core, 60 bytes

5-in($l=$args|%{($s+=1+($_-in48,55))})-and12-in$l-and$s-eq17


-42 bytes thanks to mazzy

Try it online!

• 60 bytes with splatting Oct 20, 2020 at 9:20
• Nice one! You out-golfed me by 42 bytes, do you want to post it as your own answer? Oct 21, 2020 at 2:39
• Thanks, no. This is still your solution. Just a little bit of a codeGolf Oct 21, 2020 at 8:52

Thanks to ovs for helping me reduce this

g q|r<-do x<-q;1:[0|7*x==x*x]=length r==17&&r!!5*r!!12>0


Try it online!

The first thing we do is convert the input to a sort of syllable map. That is a list of integers, one for each syllables with the following meaning:

1. Second syllable of a word
2. First syllable of a word

So with this we check that the length of is 17, that is there are 17 syllables all in all. Then we index the syllable codes at the beginning of the second and third lines. We multiply these together. If either of them is the second syllable of a word this product is zero because zero times any number is zero. And if both of them are 1 then it is not zero. So we check that this is not zero. That is to say that no line starts with the second syllable of a word.

And that's it.

• 61 bytes with length and [0,1] for two syllable numbers.
– ovs
Oct 26, 2020 at 23:15
• @ovs Nice! I was actually able to remove 3 more bytes from the improved version by avoiding concatenation. Oct 26, 2020 at 23:26
• ... and another 2 off that. This has really unlocked a great deal of potential. Oct 26, 2020 at 23:33

# 05AB1E, 12 bytes

7Ö>.œO575S.å


Input as a list of digits.

Explanation:

7Ö            # Check for each digit of the (implicit) input-list whether it's divisible
# by 7
>           # Increase these checks by 1 (2 for 0 and 7; 1 otherwise)
.œ         # Check all partitions of this list
O        # Sum each inner-most list
575S    # Push [5,7,5]
.å  # Check that this list is in the list of lists
# (after which the result is output implicitly)


# JavaScript, 53 bytes

BigInt input.

n=>!(f=s=>n?f(s-=n%10n%7n?1:s%7-6?2:18,n/=10n):s)(17)


# Husk, 22 bytes

§&o=17→§&€5€12∫mȯ→¬%7d


Try it online!

Port of my R answer so probably not the golfiest approach in Husk...

§&o=17→§&€5€12∫mȯ→¬%7d
§&                      # fork &: are both of the following true?
o=17→                 # last element equals 17?
§&               # fork &: are both of the following true?
€5             # contains 5?
€12          # contains 12?
# ...when applied to:
∫         # cumulative sum of
m     d  # this function applied to digits of input:
ȯ       # combine 3 functions:
%7   # MOD 7
¬     # NOT
→      # +1

• bit difficult to get all partitions of a list, might get up to the same bytecount. Nice answer! Oct 20, 2020 at 14:58

# C (gcc), 70 67 bytes

Thanks to ceilingcat for the -3.

Returns 0 if a valid haiku and non-zero if not.

As the syllable count can only increase by either 1 or 2, I check for 5, 12 and greater than 16 and increase the state when I see those values (this also accounts for strings that would be valid except for continuing past 17.) If the state ends at 3 by the end of the input, then it's correct.

c,d;f(char*s){for(c=d=0;*s;d+=c==5|c==12|c>16)c-=~!(~*s++%7);d-=3;}


Try it online!

# K (ngn/k), 31 30 bytes

{(17=*|o)>/^(o:+\1+~7!x)?5 12}


Try it online!

A straightforward translation of @jonah's J answer.

• (o:+\1+~7!x) convert input to number of syllables in each digit, storing in o (literally, sums 1 + not 7 mod x)
• ^(...)?5 12 check whether 5 and 12 are in that list
• (17=*|o) check whether or not the list ends up with syllable 17
• (...)>/... use greater-than-fold, seeded with (17=*|o)