- The rules for the flags
/g
and/y
are complicated. - Regular expression operations keep state in RegExp objects, via property
.lastIndex
. That leads to several pitfalls if a RegExp object is used multiple times. It also makes it impossible to freeze instances of RegExp. String.prototype.replace()
accepts a callback where accessing named captures is inconvenient (via an object that is passed as the last argument).
- Improving the RegExp API without introducing a new constructor.
Common characteristics:
- Options object:
.startIndex = 0
.returnIndices = false
- Don’t change the RegExp object in any way.
- Completely ignore
.lastIndex
.
- Completely ignore
- Completely ignore the following flags:
/g
(.global
): not needed because each method is either global or non-global/y
(.sticky
): replaced by the assertion\G
/d
(.hasIndices
): replaced by option.returnIndices
- Not as important but I’d prefer an option for a method over a RegExp flag because this toggle is more about how an operation works than about how a RegExp matches.
.execOnce(str, options?): MatchObject
.execMany(str, options?): Iteratable<MatchObject>
.testOnce(str, options?): boolean
Better callback type signature: callback(matchObject)
.replaceOnce(stringOrRegExp, stringOrCallback, options?): string
.replaceMany(stringOrRegExp, stringOrCallback, options?): string
Open questions:
- Should these methods forward to Symbol-keyed properties of
stringOrRegExp
?- Another option: turn them into
RegExp.prototype.*
methods.
- Another option: turn them into
String.prototype.search(patternStringOrRegExp): number
String.prototype.split(verbatimStringOrRegExp?, limit?): Array<string>
Open question:
- Would it make sense to support an additional argument
options
?
RegExp.prototype.exec
RegExp.prototype.test
String.prototype.match
String.prototype.matchAll
String.prototype.replace
String.prototype.replaceAll
- Matches at the current matching position (0 or
.startIndex
). - Loosely related to the
^
assertion
How should legacy methods handle \G
?
- It clashes with flag
/y
because with that flag, a regular expression implicitly starts with\G
.- Thus: throwing an exception when
\G
is used with/y
seems the best option.
- Thus: throwing an exception when
- Other than that, we could specify a “current position” for all legacy methods (sometimes
.lastIndex
, sometimes 0) and use that with\G
. /y
is ignored by.split()
, so supporting\G
would be an improvement.
- List of upcoming RegExp proposals (collapsed section “Future: Active proposals”): https://github.com/slevithan/awesome-regex#javascript-regex-evolution
- Currently, there is no plan to support multi-line RegExp literals in JavaScript. A template tag is a good alternative and would be very useful for the proposed flag
/x
. - Two TC39 members have expressed an interest in adding a template tags for RegExps to JavaScript (source).
- A template tag could look like this: https://github.com/slevithan/regex
All
is already taken.- It’s just a first idea – suggestions welcome!
- Other options:
Multi
,OnceOrMore
- Other options:
- I find non-overloaded methods easier to understand (they are also easier to statically type):
.execOnce
and.execMany
have different return types. - I also like to avoid single big methods that do too much.
- Precedents for method pairs in the current API:
.replace()
and.replaceAll()
.match()
and.matchAll()
- Thanks to Steven Levithan for inspiring this proposal and his feedback to my ideas.
@slevithan Great feedback, thanks! I updated the Gist.