Regular Expressions 101

Save & Manage Regex

  • Current Version: 1
  • Save & Share
  • Community Library

Flavor

  • PCRE2 (PHP)
  • ECMAScript (JavaScript)
  • Python
  • Golang
  • Java
  • .NET 7.0 (C#)
  • Rust
  • PCRE (Legacy)
  • Regex Flavor Guide

Function

  • Match
  • Substitution
  • List
  • Unit Tests
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
Processing...

Test String

Substitution
Processing...

Code Generator

Generated Code

re = /(?x)^ (?<StatementDesc>(?: (?: [\/\/].+(?=\n)\n)* )* ) (?: (?: # Begin Function Declaration func[[:space:]]+ # Datatype Method? (?: \( (?<funcRecvrVar>[a-zA-Z_]+) [[:space:]]+ (?<funcRecvrTypePointerChar>\*?) (?<funcRecvrType>[^[[:space:]\)]+) (?<funcRecvrErr>.*?(?=[\)])) \) )? [[:space:]]* # Function Name (?<funcName>[a-zA-Z]+) [[:space:]]* # Parameters \((?<funcParamBody> # <funcParam> is optional (?<funcParam> (?<funcParam1> (?<funcParam1Name> [A-Za-z_\d]+ (?: [[:space:]]+ (?<funcParam1Type> [A-Za-z_\d]+ [[:space:]]* )? | [[:space:]]* )? ) ) # Next Parameter recursion (?: # Check if comma (?=,)[,] [[:space:]]* (?<funcParam2> (?<funcParam2Name> [A-Za-z_\d]+ (?: [[:space:]]+ (?<funcParam2Type> [A-Za-z_\d]+ [[:space:]]* )? | [[:space:]]* )? ) ) # Next Parameter recursion (?: # Check if comma (?=,)[,] [[:space:]]* (?<funcParam3> (?<funcParam3Name> [A-Za-z_\d]+ (?: [[:space:]]+ (?<funcParam3Type> [A-Za-z_\d]+ [[:space:]]* )? | [[:space:]]* )? ) ) )? )? (?<funcParamRest>[^\)]*) )? )\) [[:space:]]* # Return Value (?: # Return inside parens (?:[\(] (?<funcReturn1>[^\),[:space:]]+) (?: [[:space:]]*[,][[:space:]]* (?<funcReturn2>[^\),[:space:]]+) (?: [[:space:]]*[,][[:space:]]* (?<funcReturn3>[^\),[:space:]]+) )? )? [\)] ) | # Single Return Outside Parens (?<funcReturnSingle>[^\{[:space:]]+) | )? [[:space:]]* [[:space:]]* ) # Remove Non-relevant lines (?<removed> (?: # At new line, check if its blank || begins with spaces or not `func` (?= (?: $ | [[:space:]\t].+\n | (?!\/\/|func) ) ) .+\n+(?=(?![\/]|func)) )+ )? )/mix str = '//test func (m *Messenger) LetterPrompt(param1 type1, param2 type2) { } // TermMessage sends a message to the user in the terminal. This usually occurs before // micro has been fully initialized -- ie if there is an error in the syntax highlighting // regular expressions // The function must be called when the screen is not initialized // This will write the message, and wait for the user // to press and key to continue func TermMessage(msg ...interface{}) { screenWasNil := screen == nil if !screenWasNil { screen.Fini() screen = nil } fmt.Println(msg...) fmt.Print("\\nPress enter to continue") reader := bufio.NewReader(os.Stdin) reader.ReadString(\'\\n\') if !screenWasNil { InitScreen() } } // TermError sends an error to the user in the terminal. Like TermMessage except formatted // as an error func TermError(filename string, lineNum int, err string) *Buffer { TermMessage(filename + ", " + strconv.Itoa(lineNum) + ": " + err) } // Messenger is an object that makes it easy to send messages to the user // and get input from the user type Messenger struct { log *Buffer // Are we currently prompting the user? hasPrompt bool // Is there a message to print hasMessage bool // Message to print message string // The user\'s response to a prompt response string // style to use when drawing the message style tcell.Style // We have to keep track of the cursor for prompting cursorx int // This map stores the history for all the different kinds of uses Prompt has // It\'s a map of history type -> history array history map[string][]string historyNum int // Is the current message a message from the gutter gutterMessage bool } // AddLog sends a message to the log view func (m *Messenger) AddLog(msg ...interface{}) { logMessage := fmt.Sprint(msg...) buffer := m.getBuffer() buffer.insert(buffer.End(), []byte(logMessage+"\\n")) buffer.Cursor.Loc = buffer.End() buffer.Cursor.Relocate() } func (m *Messenger) getBuffer() *Buffer { if m.log == nil { m.log = NewBufferFromString("", "") m.log.name = "Log" } return m.log } // Message sends a message to the user func (m *Messenger) Message(msg ...interface{}) { displayMessage := fmt.Sprint(msg...) // only display a new message if there isn\'t an active prompt // this is to prevent overwriting an existing prompt to the user if m.hasPrompt == false { // if there is no active prompt then style and display the message as normal m.message = displayMessage m.style = defStyle if _, ok := colorscheme["message"]; ok { m.style = colorscheme["message"] } m.hasMessage = true } // add the message to the log regardless of active prompts m.AddLog(displayMessage) } // Error sends an error message to the user func (m *Messenger) Error(msg ...interface{}) { buf := new(bytes.Buffer) fmt.Fprint(buf, msg...) // only display a new message if there isn\'t an active prompt // this is to prevent overwriting an existing prompt to the user if m.hasPrompt == false { // if there is no active prompt then style and display the message as normal m.message = buf.String() m.style = defStyle. Foreground(tcell.ColorBlack). Background(tcell.ColorMaroon) if _, ok := colorscheme["error-message"]; ok { m.style = colorscheme["error-message"] } m.hasMessage = true } // add the message to the log regardless of active prompts m.AddLog(buf.String()) } func (m *Messenger) PromptText(msg ...interface{}) { displayMessage := fmt.Sprint(msg...) } // YesNoPrompt asks the user a yes or no question (waits for y or n) and returns the result func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) { m.hasPrompt = true m.PromptText(prompt) _, h := screen.Size() for { m.Clear() m.Display() screen.ShowCursor(Count(m.message), h-1) screen.Show() event := <-events switch e := event.(type) { case *tcell.EventKey: switch e.Key() { case tcell.KeyRune: if e.Rune() == \'y\' || e.Rune() == \'Y\' { m.AddLog("\\t--> y") m.hasPrompt = false return true, false } else if e.Rune() == \'n\' || e.Rune() == \'N\' { m.AddLog("\\t--> n") m.hasPrompt = false return false, false } case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape: m.AddLog("\\t--> (cancel)") m.Clear() m.Reset() m.hasPrompt = false return false, true } } } } // LetterPrompt gives the user a prompt and waits for a one letter response func (m *Messenger) LetterPrompt(prompt string, responses ...rune) (rune, bool) { m.hasPrompt = true m.PromptText(prompt) _, h := screen.Size() for { m.Clear() m.Display() screen.ShowCursor(Count(m.message), h-1) screen.Show() event := <-events switch e := event.(type) { case *tcell.EventKey: switch e.Key() { case tcell.KeyRune: for _, r := range responses { if e.Rune() == r { m.AddLog("\\t--> " + string(r)) m.Clear() m.Reset() m.hasPrompt = false return r, false } } case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape: m.AddLog("\\t--> (cancel)") m.Clear() m.Reset() m.hasPrompt = false return \' \', true } } } } // Completion represents a type of completion type Completion int const ( NoCompletion Completion = iota FileCompletion CommandCompletion HelpCompletion OptionCompletion PluginCmdCompletion PluginNameCompletion OptionValueCompletion ) // Prompt sends the user a message and waits for a response to be typed in // This function blocks the main loop while waiting for input func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTypes ...Completion) (string, bool) { m.hasPrompt = true m.PromptText(prompt) if _, ok := m.history[historyType]; !ok { m.history[historyType] = []string{""} } else { m.history[historyType] = append(m.history[historyType], "") } m.historyNum = len(m.history[historyType]) - 1 response, canceled := placeholder, true m.response = response m.cursorx = Count(placeholder) RedrawAll() for m.hasPrompt { var suggestions []string m.Clear() event := <-events switch e := event.(type) { case *tcell.EventResize: for _, t := range tabs { t.Resize() } RedrawAll() case *tcell.EventKey: switch e.Key() { case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape: // Cancel m.AddLog("\\t--> (cancel)") m.hasPrompt = false case tcell.KeyEnter: // User is done entering their response m.AddLog("\\t--> " + m.response) m.hasPrompt = false response, canceled = m.response, false m.history[historyType][len(m.history[historyType])-1] = response case tcell.KeyTab: args, err := shellwords.Split(m.response) if err != nil { break } currentArg := "" currentArgNum := 0 if len(args) > 0 { currentArgNum = len(args) - 1 currentArg = args[currentArgNum] } var completionType Completion if completionTypes[0] == CommandCompletion && currentArgNum > 0 { if command, ok := commands[args[0]]; ok { completionTypes = append([]Completion{CommandCompletion}, command.completions...) } } if currentArgNum >= len(completionTypes) { completionType = completionTypes[len(completionTypes)-1] } else { completionType = completionTypes[currentArgNum] } var chosen string if completionType == FileCompletion { chosen, suggestions = FileComplete(currentArg) } else if completionType == CommandCompletion { chosen, suggestions = CommandComplete(currentArg) } else if completionType == HelpCompletion { chosen, suggestions = HelpComplete(currentArg) } else if completionType == OptionCompletion { chosen, suggestions = OptionComplete(currentArg) } else if completionType == OptionValueCompletion { if currentArgNum-1 > 0 { chosen, suggestions = OptionValueComplete(args[currentArgNum-1], currentArg) } } else if completionType == PluginCmdCompletion { chosen, suggestions = PluginCmdComplete(currentArg) } else if completionType == PluginNameCompletion { chosen, suggestions = PluginNameComplete(currentArg) } else if completionType < NoCompletion { chosen, suggestions = PluginComplete(completionType, currentArg) } if len(suggestions) > 1 { chosen = chosen + CommonSubstring(suggestions...) } if len(suggestions) != 0 && chosen != "" { m.response = shellwords.Join(append(args[:len(args)-1], chosen)...) m.cursorx = Count(m.response) } } } m.HandleEvent(event, m.history[historyType]) m.Clear() for _, v := range tabs[curTab].Views { v.Display() } DisplayTabs() m.Display() if len(suggestions) > 1 { m.DisplaySuggestions(suggestions) } screen.Show() } m.Clear() m.Reset() return response, canceled } // UpHistory fetches the previous item in the history func (m *Messenger) UpHistory(history []string) { if m.historyNum > 0 { m.historyNum-- m.response = history[m.historyNum] m.cursorx = Count(m.response) } } // DownHistory fetches the next item in the history func (m *Messenger) DownHistory(history []string) { if m.historyNum < len(history)-1 { m.historyNum++ m.response = history[m.historyNum] m.cursorx = Count(m.response) } } // CursorLeft moves the cursor one character left func (m *Messenger) CursorLeft() { if m.cursorx > 0 { m.cursorx-- } } // CursorRight moves the cursor one character right func (m *Messenger) CursorRight() { if m.cursorx < Count(m.response) { m.cursorx++ } } // Start moves the cursor to the start of the line func (m *Messenger) Start() { m.cursorx = 0 } // End moves the cursor to the end of the line func (m *Messenger) End() { m.cursorx = Count(m.response) } // Backspace deletes one character func (m *Messenger) Backspace() { if m.cursorx > 0 { m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:]) m.cursorx-- } } // Paste pastes the clipboard func (m *Messenger) Paste() { clip, _ := clipboard.ReadAll("clipboard") m.response = Insert(m.response, m.cursorx, clip) m.cursorx += Count(clip) } // WordLeft moves the cursor one word to the left func (m *Messenger) WordLeft() { response := []rune(m.response) m.CursorLeft() if m.cursorx <= 0 { return } for IsWhitespace(response[m.cursorx]) { if m.cursorx <= 0 { return } m.CursorLeft() } m.CursorLeft() for IsWordChar(string(response[m.cursorx])) { if m.cursorx <= 0 { return } m.CursorLeft() } m.CursorRight() } // WordRight moves the cursor one word to the right func (m *Messenger) WordRight() { response := []rune(m.response) if m.cursorx >= len(response) { return } for IsWhitespace(response[m.cursorx]) { m.CursorRight() if m.cursorx >= len(response) { m.CursorRight() return } } m.CursorRight() if m.cursorx >= len(response) { return } for IsWordChar(string(response[m.cursorx])) { m.CursorRight() if m.cursorx >= len(response) { return } } } // DeleteWordLeft deletes one word to the left func (m *Messenger) DeleteWordLeft() { m.WordLeft() m.response = string([]rune(m.response)[:m.cursorx]) } // HandleEvent handles an event for the prompter func (m *Messenger) HandleEvent(event tcell.Event, history []string) { switch e := event.(type) { case *tcell.EventKey: switch e.Key() { case tcell.KeyCtrlA: m.Start() case tcell.KeyCtrlE: m.End() case tcell.KeyUp: m.UpHistory(history) case tcell.KeyDown: m.DownHistory(history) case tcell.KeyLeft: if e.Modifiers() == tcell.ModCtrl { m.Start() } else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta { m.WordLeft() } else { m.CursorLeft() } case tcell.KeyRight: if e.Modifiers() == tcell.ModCtrl { m.End() } else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta { m.WordRight() } else { m.CursorRight() } case tcell.KeyBackspace2, tcell.KeyBackspace: if e.Modifiers() == tcell.ModCtrl || e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta { m.DeleteWordLeft() } else { m.Backspace() } case tcell.KeyCtrlW: m.DeleteWordLeft() case tcell.KeyCtrlV: m.Paste() case tcell.KeyCtrlF: m.WordRight() case tcell.KeyCtrlB: m.WordLeft() case tcell.KeyRune: m.response = Insert(m.response, m.cursorx, string(e.Rune())) m.cursorx++ } history[m.historyNum] = m.response case *tcell.EventPaste: clip := e.Text() m.response = Insert(m.response, m.cursorx, clip) m.cursorx += Count(clip) case *tcell.EventMouse: x, y := e.Position() x -= Count(m.message) button := e.Buttons() _, screenH := screen.Size() if y == screenH-1 { switch button { case tcell.Button1: m.cursorx = x if m.cursorx < 0 { m.cursorx = 0 } else if m.cursorx > Count(m.response) { m.cursorx = Count(m.response) } } } } } // Reset resets the messenger\'s cursor, message and response func (m *Messenger) Reset() { m.cursorx = 0 m.message = "" m.response = "" } // Clear clears the line at the bottom of the editor func (m *Messenger) Clear() { w, h := screen.Size() for x := 0; x < w; x++ { screen.SetContent(x, h-1, \' \', nil, defStyle) } } func (m *Messenger) DisplaySuggestions(suggestions []string) { w, screenH := screen.Size() y := screenH - 2 statusLineStyle := defStyle.Reverse(true) if style, ok := colorscheme["statusline"]; ok { statusLineStyle = style } for x := 0; x < w; x++ { screen.SetContent(x, y, \' \', nil, statusLineStyle) } x := 0 for _, suggestion := range suggestions { for _, c := range suggestion { screen.SetContent(x, y, c, nil, statusLineStyle) x++ } screen.SetContent(x, y, \' \', nil, statusLineStyle) x++ } } // Display displays messages or prompts func (m *Messenger) Display() { _, h := screen.Size() if m.hasMessage { if m.hasPrompt || globalSettings["infobar"].(bool) { runes := []rune(m.message + m.response) posx := 0 for x := 0; x < len(runes); x++ { screen.SetContent(posx, h-1, runes[x], nil, m.style) posx += runewidth.RuneWidth(runes[x]) } } } if m.hasPrompt { screen.ShowCursor(Count(m.message)+m.cursorx, h-1) screen.Show() } } // LoadHistory attempts to load user history from configDir/buffers/history // into the history map // The savehistory option must be on func (m *Messenger) LoadHistory() { if GetGlobalOption("savehistory").(bool) { file, err := os.Open(configDir + "/buffers/history") defer file.Close() var decodedMap map[string][]string if err == nil { decoder := gob.NewDecoder(file) err = decoder.Decode(&decodedMap) if err != nil { m.Error("Error loading history:", err) return } } if decodedMap != nil { m.history = decodedMap } else { m.history = make(map[string][]string) } } else { m.history = make(map[string][]string) } } // SaveHistory saves the user\'s command history to configDir/buffers/history // only if the savehistory option is on func (m *Messenger) SaveHistory() { if GetGlobalOption("savehistory").(bool) { // Don\'t save history past 100 for k, v := range m.history { if len(v) > 100 { m.history[k] = v[len(m.history[k])-100:] } } file, err := os.Create(configDir + "/buffers/history") defer file.Close() if err == nil { encoder := gob.NewEncoder(file) err = encoder.Encode(m.history) if err != nil { m.Error("Error saving history:", err) return } } } } // A GutterMessage is a message displayed on the side of the editor type GutterMessage struct { lineNum int msg string kind int } // These are the different types of messages const ( // GutterInfo represents a simple info message GutterInfo = iota // GutterWarning represents a compiler warning GutterWarning // GutterError represents a compiler error GutterError ) ' subst = '' result = str.gsub(re, subst) # Print the result of the substitution puts 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 Ruby, please visit: http://ruby-doc.org/core-2.2.0/Regexp.html