keep a match's quotes and brackets around the replacement in replace()
This commit is contained in:
1 parent
b3dcee7617
commit
3613d1a0e2
2 files changed
+75
-14
No files matched your search
@@ -1,3 +1,5 @@
|
|||||||
|
import fmts from '../../output/api/_fmts.js'
|
||||||
|
|
||||||
const dollarStub = /\$[0-9a-z]+/g
|
const dollarStub = /\$[0-9a-z]+/g
|
||||||
const fns = {}
|
const fns = {}
|
||||||
|
|
||||||
@@ -6,10 +8,30 @@ const isTitleCase = (str) => /^\p{Lu}[\p{Ll}'’]/u.test(str) || /^\p{Lu}$/u.tes
|
|||||||
const toTitleCase = (str) => str.replace(/^\p{Ll}/u, x => x.toUpperCase())
|
const toTitleCase = (str) => str.replace(/^\p{Ll}/u, x => x.toUpperCase())
|
||||||
const toLowerCase = (str) => str.replace(/^\p{Lu}/u, x => x.toLowerCase())
|
const toLowerCase = (str) => str.replace(/^\p{Lu}/u, x => x.toLowerCase())
|
||||||
|
|
||||||
|
// the match's pre and post are kept by replaceWith(), so m.text() should leave them out
|
||||||
|
const withoutEnds = function (m) {
|
||||||
|
const text = m.text
|
||||||
|
m.text = fmt => {
|
||||||
|
const opts = typeof fmt === 'string' ? fmts[fmt] : fmt
|
||||||
|
return text.call(m, { keepEndPunct: false, ...opts })
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// put the match's own punctuation around the replacement's, unless it already has it
|
||||||
|
const outerPre = (pre, fresh) => {
|
||||||
|
const punct = pre.trimStart()
|
||||||
|
return fresh.startsWith(punct) ? pre.slice(0, pre.length - punct.length) + fresh : pre + fresh
|
||||||
|
}
|
||||||
|
const outerPost = (post, fresh) => {
|
||||||
|
const punct = post.trimEnd()
|
||||||
|
return fresh.endsWith(punct) ? fresh + post.slice(punct.length) : fresh + post
|
||||||
|
}
|
||||||
|
|
||||||
// doc.replace('foo', (m)=>{})
|
// doc.replace('foo', (m)=>{})
|
||||||
const replaceByFn = function (main, fn, keep) {
|
const replaceByFn = function (main, fn, keep) {
|
||||||
main.forEach(m => {
|
main.forEach(m => {
|
||||||
const out = fn(m)
|
const out = fn(withoutEnds(m))
|
||||||
m.replaceWith(out, keep)
|
m.replaceWith(out, keep)
|
||||||
})
|
})
|
||||||
return main
|
return main
|
||||||
@@ -58,13 +80,23 @@ fns.replaceWith = function (input, keep = {}) {
|
|||||||
ptrs = ptrs.map(ptr => ptr.slice(0, 3))
|
ptrs = ptrs.map(ptr => ptr.slice(0, 3))
|
||||||
// original.freeze()
|
// original.freeze()
|
||||||
let oldTags = (original.docs[0] || []).map(term => Array.from(term.tags))
|
let oldTags = (original.docs[0] || []).map(term => Array.from(term.tags))
|
||||||
const originalPre = original.docs[0][0].pre
|
const originalEnds = original.docs.map(words => [words[0].pre, words.at(-1).post])
|
||||||
const originalPost = original.docs[0].at(-1).post
|
|
||||||
// slide this in
|
// slide this in
|
||||||
if (typeof input === 'string') {
|
if (typeof input === 'string') {
|
||||||
input = this.fromText(input).compute('id')
|
input = this.fromText(input).compute('id')
|
||||||
}
|
}
|
||||||
|
const fresh = input.docs[0]
|
||||||
main.insertAfter(input)
|
main.insertAfter(input)
|
||||||
|
// keep the punctuation around each match, outside the replacement's own
|
||||||
|
if (fresh) {
|
||||||
|
main.docs.forEach((words, i) => {
|
||||||
|
const [pre, post] = originalEnds[i]
|
||||||
|
words.at(-fresh.length).pre = outerPre(pre, fresh[0].pre.trimStart())
|
||||||
|
if (post) {
|
||||||
|
words.at(-1).post = outerPost(post, fresh.at(-1).post.trimEnd())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
// are we replacing part of a contraction?
|
// are we replacing part of a contraction?
|
||||||
if (original.has('@hasContraction') && main.contractions) {
|
if (original.has('@hasContraction') && main.contractions) {
|
||||||
const more = main.grow('@hasContraction+')
|
const more = main.grow('@hasContraction+')
|
||||||
@@ -84,17 +116,6 @@ fns.replaceWith = function (input, keep = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to keep some pre-punctuation
|
|
||||||
if (originalPre && main.docs[0]) {
|
|
||||||
main.docs[0][0].pre = originalPre
|
|
||||||
}
|
|
||||||
// try to keep any post-punctuation
|
|
||||||
if (originalPost && main.docs[0]) {
|
|
||||||
const lastOne = main.docs[0].at(-1)
|
|
||||||
if (!lastOne.post.trim()) {
|
|
||||||
lastOne.post = originalPost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// what should we return?
|
// what should we return?
|
||||||
const m = main.toView(ptrs).compute(['index', 'freeze', 'lexicon'])
|
const m = main.toView(ptrs).compute(['index', 'freeze', 'lexicon'])
|
||||||
if (m.world.compute.preTagger) {
|
if (m.world.compute.preTagger) {
|
||||||
|
|||||||
@@ -225,3 +225,43 @@ test('replace-with-pre-post', function (t) {
|
|||||||
|
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('replace-edge-punctuation', function (t) {
|
||||||
|
let arr = [
|
||||||
|
['"hello world" he said', '"[x]" he said'],
|
||||||
|
['he said "hello world" today', 'he said "[x]" today'],
|
||||||
|
['he said "hello world"', 'he said "[x]"'],
|
||||||
|
['(hello world) he said', '([x]) he said'],
|
||||||
|
['he said (hello world) today', 'he said ([x]) today'],
|
||||||
|
['he said hello world.', 'he said [x].'],
|
||||||
|
['"hello world" and "hello world" too', '"[x]" and "[x]" too'],
|
||||||
|
]
|
||||||
|
arr.forEach(a => {
|
||||||
|
const doc = nlp(a[0])
|
||||||
|
doc.replace('hello world', '[x]')
|
||||||
|
t.equal(doc.text(), a[1], here + 'string: ' + a[0])
|
||||||
|
})
|
||||||
|
|
||||||
|
arr = [
|
||||||
|
['"hello world" he said', '"HELLO WORLD" he said'],
|
||||||
|
['he said "hello world" today', 'he said "HELLO WORLD" today'],
|
||||||
|
['he said "hello world"', 'he said "HELLO WORLD"'],
|
||||||
|
['(hello world) he said', '(HELLO WORLD) he said'],
|
||||||
|
['hello world.', 'HELLO WORLD.'],
|
||||||
|
['"hello world" and "hello world" too', '"HELLO WORLD" and "HELLO WORLD" too'],
|
||||||
|
]
|
||||||
|
arr.forEach(a => {
|
||||||
|
const doc = nlp(a[0])
|
||||||
|
doc.replace('hello world', m => m.text().toUpperCase())
|
||||||
|
t.equal(doc.text(), a[1], here + 'function: ' + a[0])
|
||||||
|
})
|
||||||
|
|
||||||
|
let doc = nlp('"hello world" he said')
|
||||||
|
doc.replace('hello world', m => '[' + m.text() + ']')
|
||||||
|
t.equal(doc.text(), '"[hello world]" he said', here + 'function with brackets')
|
||||||
|
|
||||||
|
doc = nlp('he said "hello" today')
|
||||||
|
doc.replace('hello', '"hi"')
|
||||||
|
t.equal(doc.text(), 'he said "hi" today', here + 'quotes already in replacement')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
Reference in new issue
Block a user