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
- Searches recursively by default, while ignoring “.git`, “.svn`, `CVS` and other `VCS` directories.
- 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:
- Comparison of regular expression engines
- Regular Expressions
- Regex-Railroad-Diagram
- Verbal Expressions
- XRegExp
- RegexGen
- Useful Regex Patterns
- Awesome RegEx
—