Regular Expressions 101

Save & Share

Flavor

  • PCRE2 (PHP >=7.3)
  • PCRE (PHP <7.3)
  • ECMAScript (JavaScript)
  • Python
  • Golang
  • Java 8
  • .NET 7.0 (C#)
  • Rust
  • Regex Flavor Guide

Function

  • Match
  • Substitution
  • List
  • Unit Tests

Tools

Sponsors
There are currently no sponsors. Become a sponsor today!
An explanation of your regex will be automatically generated as you type.
Detailed match information will be displayed here automatically.
  • All Tokens
  • Common Tokens
  • General Tokens
  • Anchors
  • Meta Sequences
  • Quantifiers
  • Group Constructs
  • Character Classes
  • Flags/Modifiers
  • Substitution
  • A single character of: a, b or c
    [abc]
  • A character except: a, b or c
    [^abc]
  • A character in the range: a-z
    [a-z]
  • A character not in the range: a-z
    [^a-z]
  • A character in the range: a-z or A-Z
    [a-zA-Z]
  • Any single character
    .
  • Alternate - match either a or b
    a|b
  • Any whitespace character
    \s
  • Any non-whitespace character
    \S
  • Any digit
    \d
  • Any non-digit
    \D
  • Any word character
    \w
  • Any non-word character
    \W
  • Non-capturing group
    (?:...)
  • Capturing group
    (...)
  • Zero or one of a
    a?
  • Zero or more of a
    a*
  • One or more of a
    a+
  • Exactly 3 of a
    a{3}
  • 3 or more of a
    a{3,}
  • Between 3 and 6 of a
    a{3,6}
  • Start of string
    ^
  • End of string
    $
  • A word boundary
    \b
  • Non-word boundary
    \B

Regular Expression
No Match

r"
"
gm

Test String

Substitution

Processing...

Code Generator

Generated Code

import Foundation let pattern = #"^(/\*)(\n)(\*)(.*?)(\n)(\*/$)|(?<!:)(//)(.*?)$"# let regex = try! NSRegularExpression(pattern: pattern, options: .anchorsMatchLines) let testString = #""" // intraday.gs -- Supports downloading intraday (minute-by-minute) step data // Will not work without special permission from Fitbit // Simon Bromberg (http://sbromberg.com) // You are free to use, modify, copy any of the code in this script for your own purposes, as long as it's not for evil // If you do anything cool with it, let me know! // Note: there are minor improvements/cleanups still to be made in this file, but it should work as is if everything is setup properly // See readme on github repo for more information // Script based on post here http://quantifiedself.com/2014/09/download-minute-fitbit-data/ by Ernesto Ramirez /* * Do not change these key names. These are just keys to access these properties once you set them up by running the Setup function from the Fitbit menu */ // Key of ScriptProperty for Firtbit consumer key. var CONSUMER_KEY_PROPERTY_NAME = "fitbitConsumerKey"; // Key of ScriptProperty for Fitbit consumer secret. var CONSUMER_SECRET_PROPERTY_NAME = "fitbitConsumerSecret"; var SERVICE_IDENTIFIER = 'fitbit'; function onOpen() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var menuEntries = [ { name: "Setup", functionName: "setup" }, { name: "Authorize", functionName: "showSidebar" }, { name: "Reset", functionName: "clearService" }, { name: "Download data", functionName: "refreshTimeSeries" }]; ss.addMenu("Fitbit", menuEntries); } function isConfigured() { return getConsumerKey() != "" && getConsumerSecret() != ""; } function setConsumerKey(key) { ScriptProperties.setProperty(CONSUMER_KEY_PROPERTY_NAME, key); } function getConsumerKey() { var key = ScriptProperties.getProperty(CONSUMER_KEY_PROPERTY_NAME); if (key == null) { key = ""; } return key; } function setLoggables(loggable) { ScriptProperties.setProperty("loggables", loggable); } function getLoggables() { var loggable = ScriptProperties.getProperty("loggables"); if (loggable == null) { loggable = LOGGABLES; } else { loggable = loggable.split(','); } return loggable; } function setConsumerSecret(secret) { ScriptProperties.setProperty(CONSUMER_SECRET_PROPERTY_NAME, secret); } function getConsumerSecret() { var secret = ScriptProperties.getProperty(CONSUMER_SECRET_PROPERTY_NAME); if (secret == null) { secret = ""; } return secret; } // function saveSetup saves the setup params from the UI function saveSetup(e) { setConsumerKey(e.parameter.consumerKey); setConsumerSecret(e.parameter.consumerSecret); setLoggables(e.parameter.loggables); setFirstDate(e.parameter.firstDate); setLastDate(e.parameter.lastDate); var app = UiApp.getActiveApplication(); app.close(); return app; } function setFirstDate(firstDate) { ScriptProperties.setProperty("firstDate", firstDate); } function getFirstDate() { var firstDate = ScriptProperties.getProperty("firstDate"); if (firstDate == null) { firstDate = "2012-01-01"; } return firstDate; } function setLastDate(lastDate) { ScriptProperties.setProperty("lastDate", lastDate); } function getLastDate() { var lastDate = ScriptProperties.getProperty("lastDate"); if (lastDate == null) { var today = new Date(); lastDate = Utilities.formatDate(new Date(), SpreadsheetApp.getActive().getSpreadsheetTimeZone(),"yyyy-mm-dd"); } return lastDate; } // function setup accepts and stores the Consumer Key, Consumer Secret, Project Key, firstDate, and list of Data Elements function setup() { var doc = SpreadsheetApp.getActiveSpreadsheet(); var app = UiApp.createApplication().setTitle("Setup Fitbit Download"); app.setStyleAttribute("padding", "10px"); var consumerKeyLabel = app.createLabel("Fitbit OAuth 2.0 Client ID:*"); var consumerKey = app.createTextBox(); consumerKey.setName("consumerKey"); consumerKey.setWidth("100%"); consumerKey.setText(getConsumerKey()); var consumerSecretLabel = app.createLabel("Fitbit OAuth Consumer Secret:*"); var consumerSecret = app.createTextBox(); consumerSecret.setName("consumerSecret"); consumerSecret.setWidth("100%"); consumerSecret.setText(getConsumerSecret()); var projectKeyTitleLabel = app.createLabel("Project key: "); var projectKeyLabel = app.createLabel(ScriptApp.getProjectKey()); var firstDate = app.createTextBox().setId("firstDate").setName("firstDate"); firstDate.setName("firstDate"); firstDate.setWidth("100%"); firstDate.setText(getFirstDate()); var lastDate = app.createTextBox().setId("lastDate").setName("lastDate"); lastDate.setName("lastDate"); lastDate.setWidth("100%"); lastDate.setText(getLastDate()); // create the save handler and button var saveHandler = app.createServerClickHandler("saveSetup"); var saveButton = app.createButton("Save Setup", saveHandler); // put the controls in a grid var listPanel = app.createGrid(8, 3); listPanel.setWidget(1, 0, consumerKeyLabel); listPanel.setWidget(1, 1, consumerKey); listPanel.setWidget(2, 0, consumerSecretLabel); listPanel.setWidget(2, 1, consumerSecret); listPanel.setWidget(3, 0, app.createLabel(" * (obtain these at dev.fitbit.com, use OAuth2.0)")); listPanel.setWidget(4, 0, projectKeyTitleLabel); listPanel.setWidget(4, 1, projectKeyLabel); listPanel.setWidget(5, 0, app.createLabel("Start Date for download (yyyy-mm-dd)")); listPanel.setWidget(5, 1, firstDate); listPanel.setWidget(6, 0, app.createLabel("End date for download (yyyy-mm-dd)")); listPanel.setWidget(6, 1, lastDate); listPanel.setWidget(7, 0, app.createLabel("Very long intervals will not work; exceed Fitbit rate limit and/or function will timeout")); // Ensure that all controls in the grid are handled saveHandler.addCallbackElement(listPanel); // Build a FlowPanel, adding the grid and the save button var dialogPanel = app.createFlowPanel(); dialogPanel.add(listPanel); dialogPanel.add(saveButton); app.add(dialogPanel); doc.show(app); } function getFitbitService() { // Create a new service with the given name. The name will be used when // persisting the authorized token, so ensure it is unique within the // scope of the property store Logger.log(PropertiesService.getUserProperties()); return OAuth2.createService(SERVICE_IDENTIFIER) // Set the endpoint URLs, which are the same for all Google services. .setAuthorizationBaseUrl('https://www.fitbit.com/oauth2/authorize') .setTokenUrl('https://api.fitbit.com/oauth2/token') // Set the client ID and secret, from the Google Developers Console. .setClientId(getConsumerKey()) .setClientSecret(getConsumerSecret()) // Set the name of the callback function in the script referenced // above that should be invoked to complete the OAuth flow. .setCallbackFunction('authCallback') // Set the property store where authorized tokens should be persisted. .setPropertyStore(PropertiesService.getUserProperties()) .setScope('activity profile') .setTokenHeaders({ 'Authorization': 'Basic ' + Utilities.base64Encode(getConsumerKey() + ':' + getConsumerSecret()) }); } function clearService(){ OAuth2.createService(SERVICE_IDENTIFIER) .setPropertyStore(PropertiesService.getUserProperties()) .reset(); } function showSidebar() { var service = getFitbitService(); if (!service.hasAccess()) { var authorizationUrl = service.getAuthorizationUrl(); var template = HtmlService.createTemplate( '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' + 'Reopen the sidebar when the authorization is complete.'); template.authorizationUrl = authorizationUrl; var page = template.evaluate(); SpreadsheetApp.getUi().showSidebar(page); } else { Logger.log("Has access!!!!"); } } function authCallback(request) { Logger.log("authcallback"); var service = getFitbitService(); var isAuthorized = service.handleCallback(request); if (isAuthorized) { Logger.log("success"); return HtmlService.createHtmlOutput('Success! You can close this tab.'); } else { Logger.log("denied"); return HtmlService.createHtmlOutput('Denied. You can close this tab'); } } function getUser() { var service = getFitbitService(); var options = { headers: { "Authorization": "Bearer " + service.getAccessToken(), "method": "GET" }}; var response = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/profile.json",options); var o = JSON.parse(response.getContentText()); return o.user; } function refreshTimeSeries() { if (!isConfigured()) { setup(); return; } var user = getUser(); var doc = SpreadsheetApp.getActiveSpreadsheet(); doc.setFrozenRows(2); // two header rows doc.getRange("a1").setValue(user.fullName); doc.getRange("a1").setComment("DOB:" + user.dateOfBirth) doc.getRange("b1").setValue(user.country + "/" + user.state + "/" + user.city); var options = {headers:{ "Authorization": 'Bearer ' + getFitbitService().getAccessToken(), "method": "GET" }}; var activities = ["activities/log/steps"]; var intradays = ["activities-log-steps-intraday"]; var lastIndex = 0; for (var activity in activities) { var index = 0; var dateString = getFirstDate(); date = parseDate(dateString); var table = new Array(); while (1) { var currentActivity = activities[activity]; try { var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/" + currentActivity + "/date/" + dateString+ "/" + dateString + ".json", options); } catch(exception) { Logger.log(exception); } var o = JSON.parse(result.getContentText()); var cell = doc.getRange('a3'); var titleCell = doc.getRange("a2"); titleCell.setValue("Date"); var title = currentActivity.split("/"); title = title[title.length - 1]; titleCell.offset(0, 1 + activity * 1.0).setValue(title); var row = o[intradays[activity]]["dataset"]; for (var j in row) { var val = row[j]; var arr = new Array(2); arr[0] = dateString + ' ' + val["time"]; arr[1] = val["value"]; table.push(arr); // set the value index index index++; } date.setDate(date.getDate()+1); dateString = Utilities.formatDate(date, "GMT", "yyyy-MM-dd"); if (dateString > getLastDate()) { break; } } // Batch set values of table, much faster than doing each time per loop run, this wouldn't work as is if there were multiple activities being listed doc.getRange("A3:B"+(table.length+2)).setValues(table); } } // parse a date in yyyy-mm-dd format function parseDate(input) { var parts = input.match(/(\d+)/g); // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]]) return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based } // parse a date in 2011-10-25T23:57:00.000 format function parseDate2(input) { var parts = input.match(/(\d+)/g); return new Date(parts[0], parts[1]-1, parts[2], parts[3], parts[4]); } """# let stringRange = NSRange(location: 0, length: testString.utf16.count) let substitutionString = #"\2'\4\5\8"# let result = regex.stringByReplacingMatches(in: testString, range: stringRange, withTemplate: substitutionString) print(result)

Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Swift 5.2, please visit: https://developer.apple.com/documentation/foundation/nsregularexpression