npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-string-replace-recursively

v0.2.0

Published

replace strings that match a particular pattern with a React Component, recursively

Downloads

5,774

Readme

React String Replace Recursively

npm npm

Installation

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

Usage

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 = (
  <ParentComponent>
    ["I appreciate a good ",
     <Link key={'0-1'} to={"tags/#chairback"}>
       ["#",
        <span key={'0-1-1'} className='search-term-match'>"chair"</span>,
        "back"]
     </Link>,
     " I must say"]
  </ParentComponent>
);

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 :

<ParentComponent>{array}</ParentComponent>

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>;
    }
  },
  ...