Why does '[a-z]*' match non-alphabetical strings?

The pattern [a-z]* matches zero or more characters in the range a to z (the actual characters are dependent on the current locale). There are zero such characters at the very start of the string 123 abc (i.e. the pattern matches), and also four of them at the start of this is a line.

If you need at least one match, then use [a-z][a-z]* or [a-z]\{1,\}, or enable extended regular expressions with sed -E and use [a-z]+.

To visualize where the pattern matches, add parentheses around each match:

$ sed 's/[a-z]*/(&)/' file
()123 abc
(this) is a line

Or, to see all matches on the lines:

$ sed 's/[a-z]*/(&)/g' file
()1()2()3() (abc)
(this) (is) (a) (line)

Compare that last result with

$ sed -E 's/[a-z]+/(&)/g' file
123 (abc)
(this) (is) (a) (line)

Because * matches zero or more repetitions of the previous atom, and all regex engines try to find the first match. There's a substring of exactly zero letters in the start of your string, so that's where it matches. In the case where the string starts with a letter, the * matches as many as it can, but this is secondary to finding the leftmost match.

Zero-length matches can be a bit problematic, and as you saw, the solution is to modify the pattern so that it requires at least one character. With extended regexes, you could + for that: sed -E 's/[a-z]+/SUB/'

For fun, try:

echo 'less than 123 words' | sed 's/[0-9]*/x/g'