Update after OP's clarification:
If you'd like to only allow letter or numbers in each block, you may use:
^(?=.{8}$)(?:(?:[a-z]+|[0-9]+)(?:-|$)){3}
Demo.
If you also want to make sure the string contains both letters and numbers, you may use the following instead:
^(?=.{8}$)(?=.*[a-z])(?=.*[0-9])(?:(?:[a-z]+|[0-9]+)(?:-|$)){3}
Demo.
Original answer:
If I understand your requirements correctly, you may use something like this:
/^(?=.{8}$)[a-z0-9]{1,3}-[a-z0-9]{1,3}-[a-z0-9]{1,3}$/
Demo.
Breakdown:
^ # The beginning of the string.
(?=.{8}$) # A positive Lookahead to limit the length of the string to exactly 8 chars.
[a-z0-9]{1,3} # One to three alphanumeric (English) characters.
- # Matches the character "-" literally.
$ # The end of the string.
Update:
If you want to avoid repeating the [a-z0-9]{1,3}
part, you may use something like this:
^(?=.{8}$)(?:[a-z0-9]{1,3}(?:-|$)){3}
...but the pattern will not be as easy to read so I would stick with the first one.
References: