0.2.0 • Published 5 years ago

react-string-replace-recursively v0.2.0

Weekly downloads
Last release
5 years ago

React String Replace Recursively

npm npm


npm install react-string-replace-recursively --save


var reactStringReplace = require('react-string-replace-recursively');
var config = {
  'hashTag': {
    pattern: /(#[a-z\d][\w-]*)/ig,
    matcherFn: function (rawText, processed, key) {
      return <Link key={key} to={"tags/" + rawText}>{processed}</Link>;
  'searchTerm': {
    pattern: /(chair)/ig,
    matcherFn: function (rawText, processed, key) {
      return <span key={key} className='search-term-match'>{processed}</span>;

var inputString = "I appreciate a good #chairback I must say";
var result = reactStringReplace(config)(inputString);
var parent = <ParentComponent>{result}</ParentComponent>;

This would amount to doing :

var parent = (
    ["I appreciate a good ",
     <Link key={'0-1'} to={"tags/#chairback"}>
        <span key={'0-1-1'} className='search-term-match'>"chair"</span>,
     " I must say"]

Note that the matcherFn has three parameters : rawText, processed and key. The rawText corresponds to the section of the string which matches the pattern. The processsed parameter, however, corresponds to the result of replacing other patterns which occur within rawText. Thus if you want to replace patterns within patterns, make sure to wrap your React Components around processed as we did in this example. See Configuration and Limitations for more on pattern intersections.

The key is a string that will be unique for any substring of inputString that gets replaced. Be sure to include it within the key prop of the returned React component as we did in this example, for React asks that components in an array are provided with unique keys.

English Description

This library is for replacing substrings of a string that match a particular pattern with a React Component, taking special care to account for patterns that occur within other patterns (see Configuration and Limitations for more on pattern intersections).

For example, I use it to replace substrings matching the 'hashtag' pattern with React Link components from the react-router library. You can see it in action on this web app - crosswise.

The word replace is used loosely here because in a strict sense you can't replace a substring with something that is not a string. A string cannot have constituent parts that are not also strings themselves.

This complication is the reason this library exists, for if one were just replacing substrings with things that were also strings, one could get away with using Javascript's native String.Prototype.replace method.

To avoid the conundrum of replacing substrings with things that are not strings, the function supplied by this library creates a special array representation of its input string. This array cleaves the input string in such a way that the desired substring replacements become array-element replacements instead.

Replacing elements in this array is conundrum-free because in Javascript arrays, you can replace an element of one kind (eg String) with an element of any other kind (eg React Component).

After replacements are enacted on this special array, the array may no longer consist entirely of strings, but it will have preserved the sequential structure of the original input string.

What this means is that if substring1 precedes substring2 in the input string, then the elements in which substring1 or its replacement appears will precede the elements in which substring2 or its replacement appears.

Because sequential structure is thus maintained, the array can be used for displaying the contents of the original string (as enhanced by replacements).

In React, this is a simple affair - one needs simply place the resulting array within another component :


Configuration and Limitations

Pattern Intersections

As far as intersections go, patterns placed earlier in the config parameter will be prioritized.

Suppose that pattern1 is placed earlier than pattern2. Suppose instance1 and instance2 are instances of pattern1 and pattern2, respectively.

If instance1 partially intersects with instance2, then instance1 will be detected and replaced and instance2 will be ignored.

If instance1 occurs within instance2, then again instance1 will be detected and replaced and instance2 will be ignored.

If instance1 occurs around instance2, then by default both will be detected and replaced (see example in Usage). However, if you would like instance2 to be ignored in this case, you can specify this with the ignore key in the config hash. For example, I prefer to ignore hashtag patterns when they appear within urls :

  'url': {
    pattern: ...
    matcherFn: ...
    ignore: ['hashtag']
  'hashtag': {

Text Manipulation

Remember that, for a given pattern1 , its matcherFn must wrap a React Component around processed if we desire to replace other patterns that occur within an instance of pattern1 as well.

Suppose in addition to this, we want to manipulate the string that gets shown within processed, ie the string in which our procedure will make any further pattern replacements.

For example, suppose our regular expression for inline code happened to capture the surrounding back-ticks. We can use a regular expression that doesn't do this, but for the sake of example, let's suppose we're using one that does.

In this case, we'd want to remove those back-ticks from strings matching the pattern once those strings are detected, and before they are subjected to replacements based on instances of patterns that can occur within the inline-code pattern (such as search term matches).

In order to perform a text manipulation like this, supply a textFn in the pattern's config. Below is the textFn that would be used with inline-code in the hypothetical example :

  'inlineCode': {
    pattern: /(`[\s\S]+?`)/ig,
    textFn: function (text) {
      return text.slice(1, text.length -1);
    matcherFn: function (rawText, processed) {
      return <code>{processed}</code>;