title: Is it a digit haiku?

text:
# Question
Title: 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.

## Task

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

```

# Answer
> 8 votes
# 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.

# Answer
> 7 votes
# , 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?

# Answer
> 7 votes
# 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.

# Answer
> 6 votes
# 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

# Answer
> 6 votes
# 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.

# Answer
> 4 votes
# 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!

# Answer
> 4 votes
# 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.

# Answer
> 4 votes
# , ~~72~~ ~~66~~ ~~65~~ 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!

# Answer
> 3 votes
# 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 `0`s 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).

# Answer
> 3 votes
# Perl 5 (`-p`), ~~38~~, 34 bytes

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

```

Try it online!

# Answer
> 2 votes
# 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!

# Answer
> 2 votes
# Haskell, ~~62~~ ~~58~~ 56 bytes

*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:

0. Second syllable of a word
1. 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.

# Answer
> 1 votes
# 05AB1E, 12 bytes

```
7Ö>.œO575S.å

```

Input as a list of digits.

Try it online or verify all test cases.

**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)

```

# Answer
> 1 votes
# JavaScript, 53 bytes

`BigInt` input.

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

```

# Answer
> 1 votes
# 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

```

# Answer
> 1 votes
# 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!

# Answer
> 1 votes
# 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)`

---
Tags: code-golf, string, decision-problem
---