I think rejecting any $str containing anything which isn't a cipher, comma or dot prior to eval $str should be good enough
Not quite, since it would also accept ",....," and other things like that (one of the things I meant with "other subtle bugs"). Personally I would suggest both a regex like /\A(\d+(?:\.\.\d+)?)(?:,(?1))*\z/ and checking eval for errors. And at that level, the complexity is high enough that something like* tybalt89's solution is probably better.
* Update: By which I mean, something like tybalt89's solution with some added error checking ;-)