If you're looking to tackle a similar issue, building on the functionality of breakAt
can be a good starting point. breakAt
essentially splits a string at specified cut points, while a function like intoPairs
breaks a list into its contiguous pairs. This can have various practical uses within your application.
Here's an example implementation following this approach:
const intoPairs = xs => xs.slice(1).map((x, i) => [xs[i], x])
const breakAt = (places, str) => intoPairs([0, ...places, str.length]).map(
([a, b]) => str.substring(a, b)
)
const getText = (offset, length, str) => breakAt([offset, offset + length], str)
const str = "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page."
console.log(getText(83, 16, str))
The output format may not be clear, but in this example, an array is generated containing the text before, within, and after the specified offset
, length
, and str
.
Update
In response to a follow-up question regarding breaking out multiple sub-strings, this updated version of the function allows for multiple offset
/length
pairs to further break down the text. The pairs are sorted to simplify the process, but potential overlaps are left to be handled by the user.
const intoPairs = xs => xs.slice(1).map((x, i) => [xs[i], x])
const breakAt = (places, str) => intoPairs([0, ...places, str.length]).map(
([a, b]) => str.substring(a, b)
)
const breakWhere = (words, str) => breakAt(
words.sort(({ offset: o1 }, { offset: o2 }) => o1 - o2).reduce(
(a, { offset, length }) => [...a, offset, offset + length],
[]
),
str
)
const str = "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page."
console.log(breakWhere([
{ offset: 83, length: 16 }, // "customer support"
{ offset: 12, length: 9 }, // "questions"
{ offset: 25, length: 8 }, // "comments"
], str))
The slice
call in the function is used to avoid mutation of the list of offset/length
pairs. This can be omitted if necessary.
Another Update
Addressing another follow-up question about formatting the output into nodes to differentiate between plain text and links, this version of the function creates nodes based on the data provided. Each node is tagged as either 'text' or 'link', with link nodes containing an additional 'path' property.
const intoPairs = xs => xs.slice(1).map((x, i) => [xs[i], x])
const breakAt = (places, str) => intoPairs([0, ...places, str.length]).map(
([a, b]) => str.substring(a, b)
)
const breakWhere = (words, str) => breakAt(
words.reduce((a, { offset, length }) => [...a, offset, offset + length], []),
str
)
const createNodes = (links, str) => {
const sortedLinks = links.slice(0).sort(({ offset: o1 }, { offset: o2 }) => o1 - o2)
return breakWhere(sortedLinks, str).map((s, i) => i % 2 === 0
? { data: s, type: 'text' }
: { data: s, type: 'link', path: sortedLinks[(i - 1) / 2].path }
).filter(({ data }) => data.length > 0)
}
const str = "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page."
const links = [
{offset: 83, length: 16, path: '/path/to/custSupport'},
{offset: 12, length: 9, path: 'path/to/questions'},
{offset: 25, length: 8, path: 'path/to/comments'},
]
console.log(createNodes(links, str))
This function creates nodes based on the provided links, categorizing them as 'text' or 'link' nodes with an optional 'path' property. The filtering step at the end removes any potentially empty text nodes resulting from the node creation process.
Overall, this approach is designed in a layered manner, building upon helper functions to achieve the desired functionality. While it may not be optimized for performance due to its layered nature, it offers flexibility and adaptability to changing requirements.