You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Trouble formatting bold/italic/underline text with capture group regex #33
I'm having trouble using reactStringReplace to format text with bold/italic tags. I have it set up as follows:
vartext1="[b]Testing bold [i]and italic[/i] tags[/b]"vartext2="[b]Testing bold [i]and italic tags[/b][/i]"letreplaced=reactStringReplace(text1,/\[b\]([\s\S]+)\[\/b\]/g,(match,i)=>{return<bkey={i}>{match}</b>})replaced=reactStringReplace(replaced,/\[i\]([\s\S]+)\[\/i\]/g,(match,i)=>{return<ikey={i}>{match}</i>})// result (html)<b>Testing[i]boldanditalic[/i]tags</b><b>Testing [i]bold and italic tags</b>[/i]
I'm not sure if this is a problem with reactStringReplace, with the regex I'm using, or something else. If I apply the italic replace first, I get italic tags where I'd expect them to be, but the [b] tags remain unchanged. Is this use case possible using reactStringReplace or do I need to use dangerouslySetInnerHtml?
Bonus: is reactStringReplace capable of handling unbalanced tags, or improperly formatted tags as in text2 or should I be doing some pre-processing to ensure the strings are properly balanced and formatted?
Hey @CaptainStiggz, yeah this lib does not handle nested replacements. The reason being, it's meant to be roughly equivalent to String.prototype.replace in it's functionality, however, it is true that we run into limitations since replacements can change the data type to something other than strings.
If you look here you'll see that it only runs replacements on strings. Once your first replacement has been run the element in the result array will be an object (i.e. <b>...</b>) so no replacements will be run on the inner string.
I'm open to suggestions if you have thoughts about how we might support more robust replacements.
To your second point, it just depends on the regex. If you can craft a regex that handles unbalanced/malformed tags then it should work fine. But there's no internal logic here to augment the functionality of the regex.
Thanks @iansinnott! I've been fooling around with a recurisive augmentation as follows. It's still pretty rough, but it might be useful. This modification, combined with a slight modification to the regex I originally suggested (/\[i\]([\s\S]+)\[\/i\]/g should be lazy: /\[i\]([\s\S]+?)\[\/i\]/g) seems to work pretty well.
This is a decent start, but still runs into some troublesome edge cases. For example, depending on the ordering of the bold/italic tags, I might end up with something like this:
consttext="[i][b]this should be bold and italic[/b][/i]"// const text = "[b][i]this should be bold and italic[/i][/b]" - this would workletreplaced=reactStringReplace(text,/\[b\]([\s\S]+?)\[\/b\]/g,(match,i)=>{return<bkey={i}>{match}</b>})replaced=reactStringReplace(replaced,/\[i\]([\s\S]+?)\[\/i\]/g,(match,i)=>{return<ikey={i}>{match}</i>})// replaced => [// "[i]",// <b>this should be bold and italic</b>,// "[/i]"// ]
The problem gets pretty tricky here. Not exactly sure how I want to handle such cases.
You might consider using the React.Children API for the recursion in this case, since it will handle children regardless of whether it's a single element or an array. You would just need to check if the current item being iterated over was a react element.
That being said, you're use case is essentially a new rich text markup, which might be beyond the scope of simple regex and string replacement. You might consider using a stack to help you track opening/closing brackets and build up a deeply nested data structure representing your markup. Or do something like DraftJS does and annotate each character in the string with metadata which you subsequently use to render the markup. In either case you'll probably end up having to revert to strings and dangerouslySetInnerHTML.
Activity
iansinnott commentedon May 25, 2018
Hey @CaptainStiggz, yeah this lib does not handle nested replacements. The reason being, it's meant to be roughly equivalent to
String.prototype.replacein it's functionality, however, it is true that we run into limitations since replacements can change the data type to something other than strings.If you look here you'll see that it only runs replacements on strings. Once your first replacement has been run the element in the result array will be an object (i.e.
<b>...</b>) so no replacements will be run on the inner string.I'm open to suggestions if you have thoughts about how we might support more robust replacements.
To your second point, it just depends on the regex. If you can craft a regex that handles unbalanced/malformed tags then it should work fine. But there's no internal logic here to augment the functionality of the regex.
zstiggz commentedon May 26, 2018
Thanks @iansinnott! I've been fooling around with a recurisive augmentation as follows. It's still pretty rough, but it might be useful. This modification, combined with a slight modification to the regex I originally suggested (
/\[i\]([\s\S]+)\[\/i\]/gshould be lazy:/\[i\]([\s\S]+?)\[\/i\]/g) seems to work pretty well.This is a decent start, but still runs into some troublesome edge cases. For example, depending on the ordering of the bold/italic tags, I might end up with something like this:
The problem gets pretty tricky here. Not exactly sure how I want to handle such cases.
iansinnott commentedon May 27, 2018
You might consider using the
React.ChildrenAPI for the recursion in this case, since it will handle children regardless of whether it's a single element or an array. You would just need to check if the current item being iterated over was a react element.That being said, you're use case is essentially a new rich text markup, which might be beyond the scope of simple regex and string replacement. You might consider using a stack to help you track opening/closing brackets and build up a deeply nested data structure representing your markup. Or do something like DraftJS does and annotate each character in the string with metadata which you subsequently use to render the markup. In either case you'll probably end up having to revert to strings and
dangerouslySetInnerHTML.DraftJS character metadata: https://draftjs.org/docs/api-reference-character-metadata.html