Somehow, it is a valid question. I learned quite recently REs, partly because they weren't available (natively) in my early languages (Basic, assembly, C...), partly because I found them overly complex.
Once I dived and learned them properly, I found them powerful, useful and not so complex once the eye is used to the syntax. Exploding complex expressions to multi-line syntax with indenting might help too.
They are complex because they use plain Ascii, making necessary to escape plain characters. It is even messier in languages like Java which have no way to disable escaping, so you need to double all backslashes.
But compactness is useful, somehow, you probably prefer to use /^\d{1,4}-\w+,?\d{3}$/
than several lines of parsing code. If you use Posix syntax for character classes, it might be more readable too.
Advantages of compactness can be argued (like Cobol, close of plain English, vs. APL, full of cryptic symbols), but now that regexes are well implanted in the programming world, it is a bit hard to change...
I would add that most REs I use are quite simple, like the above (you might find it not so simple... :-)). Newbies tend to complicate things with over-escaping and ignoring shortcuts: /^[0-9][0-9]?[0-9]?[0-9]?\-[A-Za-z0-9_]+\,?[0-9][0-9][0-9]$/
for the above expression isn't uncommon... (primitive regex implementations doesn't help...).
If you use excessively complex REs, with lot of pipe/alternatives, lookaround, etc., you might want to use broader REs and code to handle sub-cases: it is easier to write, understand and maintain, and might be much faster...
There are not so much alternatives, partly because there are so much REs ready to use...
Something to explore is Parsing expression grammar which is more powerful (context, nesting...) than REs and might be more readable, by using symbols.
But there aren't so much implementations. A good one is LPeg, for Lua. Here is an example of parsing arithmetic expressions:
-- Lexical Elements
local Space = lpeg.S(" \n\t")^0
local Number = lpeg.C(lpeg.P"-"^-1 * lpeg.R("09")^1) * Space
local FactorOp = lpeg.C(lpeg.S("+-")) * Space
local TermOp = lpeg.C(lpeg.S("*/")) * Space
local Open = "(" * Space
local Close = ")" * Space
-- Grammar
local Exp, Term, Factor = lpeg.V"Exp", lpeg.V"Term", lpeg.V"Factor"
G = lpeg.P{ Exp,
Exp = lpeg.Ct(Factor * (FactorOp * Factor)^0);
Factor = lpeg.Ct(Term * (TermOp * Term)^0);
Term = Number + Open * Exp * Close;
}
G = Space * G * -1
It might be still a bit cryptic for the unprepared eye, but so are most new languages. Usage of English words helps the global understanding, though.