Skip to content
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

How to use capture groups in combination with find/wrap attributes? #69

Open
ardcore opened this issue Dec 4, 2017 · 8 comments
Open
Milestone

Comments

@ardcore
Copy link

ardcore commented Dec 4, 2017

Hi,
I need to emulate a regular expression with a negative lookahead, which is, AFAIK, not supported in JS. This can be achieved with capture groups, but, when using the wrap attribute, I have no access to them.
Example: in the expression /(This)(\s+)(document)/ I need to wrap the document part with an element, but only if it's preceded by This.
I can't find a way to achieve this with the current API, any suggestions?

@padolsey
Copy link
Owner

padolsey commented Dec 4, 2017

I usually recommend passing a replace function if you want finer control over what's replaced. But in this case, a quick hack is much simpler / less painful:

findAndReplaceDOMText(document.body, {
  find: /(This)(\s+)(document)/,
  wrap: 'em'
});
findAndReplaceDOMText(document.body, {
  find: /(This)(\s+)(document)/,
  replace: '$3'
});

We're first wrapping the entire match and then replacing the innards with the latter capture group.

@ardcore
Copy link
Author

ardcore commented Dec 4, 2017

Correct me if I'm wrong, but as I understand, this would wrap the entire match and then replace the text with the capture group, which is not my goal -- I don't need to replace anything, just to wrap the specific capture group (leaving other groups intact)

@padolsey
Copy link
Owner

padolsey commented Dec 4, 2017

Ah whoops. Is document a fixed term? Because if so you could just match the entire regex and replace the last capture group with a token, and then replace that token with document:

findAndReplaceDOMText(document.body, {
  find: /(This)(\s+)(document)/g,
  replace: '$1$2__UNIQ_TOKEN__'
});
findAndReplaceDOMText(document.body, {
  find: /__UNIQ_TOKEN__/g,
  wrap: 'em',
  replace: 'document'
});

This isn't ideal, but it's quite tricky to do otherwise. As mentioned you can pass a replace function and provide the replacement nodes yourself, but that gets painful quite quickly, especially when having to consider matches across node boundaries..

@ardcore
Copy link
Author

ardcore commented Dec 4, 2017

No, unfortunately it's not a fixed term; I'm generating the whole expression dynamically based on the user text selection, and working across node boundaries is the main reason I've decided to go with findAndReplaceDOMText :) To make things even more complicated: double-running findAndReplaceDOMText may be hard in my case, because I'm also using filterElements and check against to selection.containsNode, and wrapping/replacing will influence the selection.

@ardcore
Copy link
Author

ardcore commented Dec 4, 2017

I gave it a try -- actually the solution/hack you proposed would work in my case, even with document not being fixed, however, using replace as the first pass breaks the structure/formatting (because it strips HTML, and the expression may also span over multiple nodes)

@padolsey
Copy link
Owner

padolsey commented Dec 4, 2017

Maybe on the first pass, instead of replacing it wholesale with a unique token, you can insert unique delimiters and then replace them later:

findAndReplaceDOMText(document.body, {
  find: /(This)(\s+)(document)/g,
  replace: '$1$2<<<$3>>>'
});
findAndReplaceDOMText(document.body, {
  find: /<<<(.+?)>>>/g,
  replace: '$1',
  wrap: 'em'
})

Seems like an ugly approach but TBH I can't think of one less painful.

@ardcore
Copy link
Author

ardcore commented Dec 5, 2017

Thanks, although hacky, this seems to help! I've noticed one more thing when testing it and created a separate issue: #70

@padolsey
Copy link
Owner

padolsey commented Dec 6, 2017

Gonna add this to the 1.0 milestone as I'd like this kind of thing to be simpler in the future and less reliant on hacky code.

@padolsey padolsey added this to the 1.0.0 milestone Dec 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants