Blog

RegExp: Match, Search, Replace and Split Like a Master

Today, it is well known that almost every computing sector uses `regex` to find patterns inside and through very large amounts of data or streams. For this reason, and just to figure out how to make my life easier, I found myself on the path to mastering regular expressions. In this post, I want to show you the beauty of regular expressions.

Develop a Zen mind

RegEx is one of those ‘things’ you get much better at with practice. This is why I really enjoy solving a genuinely simple problem in a simple way. Here is where I take up a rational coding mindset, always looking around and noticing patterns, relationships, and connections between ‘stuff’.

If you are a coder with several years of experience, then regular expressions are something that you should already know. Note: Not all coders have to worry about these things in their everyday tasks. But, regardless of what language you are working in, you will discover that they even serve to heal broken hearts: 

const data = 'This is my 💔';

// the flag `u` is optional when using ES6.
const pattern = /💔/gu;

const info = data.replace(pattern, '❤️');

// This is my ❤️
console.log(info);

Pick the right things first

The beauty of regular expressions lies in their velocity to find text which matches a pattern, to replace the matching data, or to split the matching data into useful and very descriptive groups of information.

const fullNamePattern = /(.+),\s?(.+)/i;

// Destructuring Assignment.
const [match, lastName, firstName] = fullNamePattern.exec("Orozco Marin , Jose Pablo") ||
[];

// Hi Jose Pablo!
console.log(`Hi ${firstName}!`);

Problems are not as complicated as we initially thought

Honestly, when solving a problem becomes a complex task, I tend to keep myself open minded and with the right attitude to dive into diverse alternatives as possible. What I usually try to do is to use the power of words to my advantage. I use this strategy as I unstuck myself from a roadblock, by simply asking the right questions or sharing the right stuff to the right people. I only show them and ask for advice on what to do and what they found or did in similar situations. 

“There’s more than one way to do it” — Perl motto.

const fullNamePattern = /(.+),\s?(.+)/i;

// Rest Operator (...) returns the remaining elements as an array.
const [match, ...name] = fullNamePattern.exec("Orozco, Pablo") || [];

// Hi Pablo!
console.log(`Hi ${name[1]}!`);

Make weird or complex things easier

// Transform a string into a boolean value.

const claim = "true";
const result = /true/gi.test(claim);

console.log(`Your claim is ${result}`);

brew install ack

  1. Searches recursively by default, while ignoring “.git`, “.svn`, `CVS` and other `VCS` directories.
  2. Is shorter than “grep” to type.
ack "\b(import|require)\b" --js

Result

actions/index.js
1:import { CALL_API, Schemas } from '../middleware/api'

components/Explore.js
1:import React, { Component, PropTypes } from 'react'

components/List.js
1:import React, { Component, PropTypes } from 'react'
components/Repo.js
1:import React, { PropTypes } from 'react'
2:import { Link } from 'react-router'

components/User.js
1:import React, { PropTypes } from 'react'
2:import { Link } from 'react-router'

containers/App.js
1:import React, { Component, PropTypes } from 'react'
2:import { connect } from 'react-redux'
3:import { browserHistory } from 'react-router'
4:import Explore from '../components/Explore'
5:import { resetErrorMessage } from '../actions'

containers/DevTools.js
1:import React from 'react'
2:import { createDevTools } from 'redux-devtools'
3:import LogMonitor from 'redux-devtools-log-monitor'
4:import DockMonitor from 'redux-devtools-dock-monitor'

containers/RepoPage.js
1:import React, { Component, PropTypes } from 'react'
2:import { connect } from 'react-redux'
3:import { loadRepo, loadStargazers } from '../actions'
4:import Repo from '../components/Repo'
5:import User from '../components/User'
6:import List from '../components/List'

containers/Root.dev.js
1:import React, { PropTypes } from 'react'
2:import { Provider } from 'react-redux'
3:import routes from '../routes'
4:import DevTools from './DevTools'
5:import { Router } from 'react-router'

containers/Root.js
2: module.exports = require('./Root.prod')
4: module.exports = require('./Root.dev')

containers/Root.prod.js
1:import React, { Component, PropTypes } from 'react'
3:import { Provider } from 'react-redux'
5:import routes from '../routes'
7:import { Router } from 'react-router'

containers/UserPage.js
1:import React, { Component, PropTypes } from 'react'
2:import { connect } from 'react-redux'
3:import { loadUser, loadStarred } from '../actions'
4:import User from '../components/User'
5:import Repo from '../components/Repo'
6:import List from '../components/List'
7:import zip from 'lodash/zip'

index.js
1:import React from 'react'
2:import { render } from 'react-dom'
4:import { browserHistory } from 'react-router'
5:import { syncHistoryWithStore } from 'react-router-redux'
7:import Root from './containers/Root'
9:import configureStore from './store/configureStore'

middleware/api.js
1:import { Schema, arrayOf, normalize } from 'normalizr'
2:import { camelizeKeys } from 'humps'

reducers/index.js
1:import * as ActionTypes from '../actions'
2:import merge from 'lodash/merge'
3:import paginate from './paginate'
4:import { routerReducer as routing } from 'react-router-redux'
5:import { combineReducers } from 'redux'

reducers/paginate.js
1:import union from 'lodash/union'

routes.js
1:import React from 'react'
3:import { Route } from 'react-router'
5:import App from './containers/App'
6:import UserPage from './containers/UserPage'
7:import RepoPage from './containers/RepoPage'

store/configureStore.dev.js
1:import { createStore, applyMiddleware, compose } from 'redux'
2:import thunk from 'redux-thunk'
3:import createLogger from 'redux-logger'
4:import api from '../middleware/api'
5:import rootReducer from '../reducers'
6:import DevTools from '../containers/DevTools'
21:      const nextRootReducer = require('../reducers').default

store/configureStore.js
2: module.exports = require('./configureStore.prod')
4: module.exports = require('./configureStore.dev')

store/configureStore.prod.js
1:import { createStore, applyMiddleware } from 'redux'
2:import thunk from 'redux-thunk'
4:import api from '../middleware/api'
5:import rootReducer from '../reducers'

List by a specific type of file

ack -f --js

Result

src/actions/index.js
src/components/Explore.js
src/components/List.js
src/components/Repo.js
src/components/User.js
src/containers/App.js
src/containers/DevTools.js
src/containers/RepoPage.js
src/containers/Root.dev.js
src/containers/Root.js
src/containers/Root.prod.js
src/containers/UserPage.js
src/index.js
src/middleware/api.js
src/reducers/index.js
src/reducers/paginate.js
src/routes.js
src/store/configureStore.dev.js
src/store/configureStore.js
src/store/configureStore.prod.js

Experienced hackers must have in mind

It is very common to make use of regular expressions to parse or extract data from text and we often use them to validate that some text conforms to a specific pattern.

Have you ever heard of `grep -E`?

Unlike `ack`, please consider `grep` as a regular expression matcher, not an advanced syntax highlighter.

egrep -Ril --include *\.js 'import|require' . | egrep -v 'node_modules|\.git'

Result

./src/actions/index.js
./src/components/Explore.js
./src/components/List.js
./src/components/Repo.js
./src/components/User.js
./src/containers/App.js
./src/containers/DevTools.js
./src/containers/RepoPage.js
./src/containers/Root.dev.js
./src/containers/Root.js
./src/containers/Root.prod.js
./src/containers/UserPage.js
./src/index.js
./src/middleware/api.js
./src/reducers/index.js
./src/reducers/paginate.js
./src/routes.js
./src/store/configureStore.dev.js
./src/store/configureStore.js
./src/store/configureStore.prod.js

Working on “large amounts” of data

egrep '^neuron' /usr/share/dict/words

Result

neuron
neuronal
neurone
neuronic
neuronism
neuronist
neuronophagia
neuronophagy
neuronym
neuronymy

Display line numbers

egrep -n '^neuron' /usr/share/dict/words

Result

123988:neuron
123989:neuronal
123990:neurone
123991:neuronic
123992:neuronism
123993:neuronist
123994:neuronophagia
123995:neuronophagy
123996:neuronym
123997:neuronymy

Count number of matches

egrep -c '^neuron' /usr/share/dict/words

Result

10

Display all lines with exactly 24 characters

egrep -n '^.{24}$' /usr/share/dict/words

Result

72632:formaldehydesulphoxylate
140339:pathologicopsychological
175108:scientificophilosophical
200796:tetraiodophenolphthalein
203042:thyroparathyroidectomize

For fun

egrep -n '^root:' /etc/passwd

egrep -w '^root' /etc/passwd

egrep -Ri --color=always "error" /var/log/wifi.log | tail -n15

// On Linux
egrep -n $(whoami) /etc/passwd
```

Search and replace

Regular expressions’ power for extracting specific text from documents resides in their ability to replace many lines of code with as little as one line. — Mark A. Anawis.

Please suppose we have the following file: test.js

/**
 * LET
 * Let
 * let
 * your letter
 */

// let id is our lucky number
let id = '333';

perl -p -i.bak -e ‘s/let/const/g’ test.js

/**
 * LET
 * Let
 * const
 * your constter
 */

// const id is our lucky number.
const id = '333';

perl -p -i.bak -e “s/\blet\b/const/g” test.js

/**
 * LET
 * Let
 * const
 * your letter
 */

// const id is our lucky number.
const id = '333';

Do you like challenges

Please keep `let’s go` string intact:

/**
 * LET
 * Let
 * let
 * let's go          <=== keep it, don't touch it
 */

// let id is our lucky number
let id = '333';

Happy Hacking!!!

Well, I am curious and I’ve got to get going

Before leaving this amazing topic, do you mind if I just ask what the toughest RegEx Challenge you have ever faced? Comment below with your experience. I believe this a great way to learn more from others.

Thanks for coming here today!

Useful resources:

Ready to be Unstoppable? Partner with Gorilla Logic, and you can be.

TALK TO OUR SALES TEAM