-
Notifications
You must be signed in to change notification settings - Fork 632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(text/unstable): add replaceStart
, replaceEnd
, replaceBoth
functions (#6265)
#6286
base: main
Are you sure you want to change the base?
Conversation
strip
function (#6265)strip
, stripStart
, stripEnd
functions (#6265)
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #6286 +/- ##
==========================================
- Coverage 96.52% 96.34% -0.19%
==========================================
Files 533 548 +15
Lines 40871 41708 +837
Branches 6120 6316 +196
==========================================
+ Hits 39451 40182 +731
- Misses 1378 1483 +105
- Partials 42 43 +1 ☔ View full report in Codecov by Sentry. |
text/unstable_strip.ts
Outdated
const count = options?.count ?? Infinity; | ||
|
||
for (let i = 0; i < count; ++i) { | ||
str = str.replace(regExp, ""); | ||
if (str === prev) break; | ||
prev = str; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why Infinity
? If the string doesn't include the pattern to strip, it will loop forever, won't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why
Infinity
? If the string doesn't include the pattern to strip, it will loop forever, won't it?
It'll break on the str === prev
condition as soon as there's nothing left to strip.
const aaa = 'a'.repeat(1000)
const aab = aaa + 'b'
const bbb = 'b'.repeat(1000)
stripStart(aaa, 'a') === ''
stripStart(aab, 'a') === 'b'
stripStart(bbb, 'a') === bbb
I think the |
@timreichen Probably worth getting some more use cases, but if I grep my code for functions named // strip(str, /[^\p{L}\p{M}]+/gu, { count: Infinity })
function stripNonLetter(str: string) {
return str.replaceAll(/^[^\p{L}\p{M}]+|[^\p{L}\p{M}]+$/gu, '')
}
// strip(str, /[_\- ]+/g, { count: Infinity })
const strip = (str: string) => str.replaceAll(/^[_\- ]+|[_\- ]+$/g, '') There are also a few cases where they strip a single instance at the start or end and then stop there, and it sounds like @canac 's use case fits here: // stripStart(str, '\ufeff', { count: 1 })
function stripBom(str: string) {
return str.replace(/^\ufeff/, '')
} I guess the "strip up to I'm not keen on the idea of doubling the API surface area from Another way of supporting single/all, but without a specific option, would be reading the |
I agree,
I wouldn't like that either. I think the problem here is that the functions are explicit in name but might work differently depending on the passed regexp.
Come to think of it, this api is tries to do too much combining all these rust functions into one imo. There is String.prototype.replace, String.prototype.replaceAll, which already cover a lot of use cases. This api should be reduced to strip_prefix => N replacements can be handled by the regexp, using a prepared string or calling the function repeatedly: |
@timreichen None of these are really satisfactory for the case where you want to dynamically strip arbitrarily many occurrences of an arbitrary string, but none of the use cases I've found involve doing that anyway — use cases with unlimited occurrences typically seem to be more suited to regex, where you can trivially use a non-capturing group along with As for replaceEnd(url.pathname, /\/*/, '/') // pathname always ends with slash
stripEnd(url.pathname, /\/*/) + '/' // same result But it could be useful for cases like this: // only prepend 'https:' when replacing existing 'http:' protocol
replaceStart(url.href, 'http:', 'https:')
// doesn't work with `strip` version as the protocol might be something else
// e.g. you might end up with `https:file:///...`
'https:' + stripStart(url.href, 'http:') Using the name 'abcxyzabcxyz'.replace(/[abc]+/, '<$&>') // '<abc>xyz<abc>xyz'
// naive result would be `<$&>xyzabcxyz`
// but seems reasonable to expect result to be `<abc>xyzabcxyz`
replaceStart('abcxyzabcxyz', /[abc]+/, '<$&>') Conversely, supporting callback replacements would be trivial, as you can just conditionalize the replacement based on whether the index lies at the start/end. replaceStart('abcxyzabcxyz', /[abc]+/, (m) => `<${m}>`) Also, the name |
strip
, stripStart
, stripEnd
functions (#6265)replace
, replaceStart
, replaceEnd
functions (#6265)
replace
, replaceStart
, replaceEnd
functions (#6265)replaceStart
, replaceEnd
, replaceBoth
functions (#6265)
How about just |
Resolves #6265.
Roughly speaking, these replicate the combined functionality of
trim_matches
,trim_start_matches
,trim_end_matches
,strip_prefix
, andstrip_suffix
(plus a hypotheticalstrip_prefix_and_suffix
) from the Rust standard library.