title: Cannot search regex in Tkinter Text Widget
body: <p>I'm trying to develop <code>Find and Replace</code> for my text editor. Unfortunately <code>regex</code> doesn't seem to work. This is very strange because I am searching the <code>Text</code> widget with the <code>regex</code> search in Python. I am suspecting the problem lies in incorrect lengths for the regex trem.</p>
  
  <p>I get the following error:</p>
  
  <pre><code>_tkinter.TclError: bad text index ""
  </code></pre>
  
  <p>Below is my <code>Python</code> code:</p>
  
  <pre><code>import tkinter as tk
  import tkinter.filedialog
  import traceback
  import tkinter.ttk as ttk
  
  from pygments import lex
  from pygments.lexers import PythonLexer
  
  import sys
  import os
  
  import re
  
  import time
  
  class CustomText(tk.Text): 
      def __init__(self, *args, **kwargs):
          tk.Text.__init__(self, *args, **kwargs)
  
          self.tk.eval('''
              proc widget_proxy {widget widget_command args} {
  
                  # call the real tk widget command with the real args
                  set result [uplevel [linsert $args 0 $widget_command]]
  
                  # generate the event for certain types of commands
                  if {([lindex $args 0] in {insert replace delete}) ||
                      ([lrange $args 0 2] == {mark set insert}) || 
                      ([lrange $args 0 1] == {xview moveto}) ||
                      ([lrange $args 0 1] == {xview scroll}) ||
                      ([lrange $args 0 1] == {yview moveto}) ||
                      ([lrange $args 0 1] == {yview scroll})} {
  
                      event generate  $widget &lt;&lt;Change&gt;&gt; -when tail
                  }
  
                  # return the result from the real widget command
                  return $result
              }
              ''')
          self.tk.eval('''
              rename {widget} _{widget}
              interp alias {{}} ::{widget} {{}} widget_proxy {widget} _{widget}
          '''.format(widget=str(self)))
  
          self.comment = False
  
      def highlight_pattern(self, pattern, tag, regex, start="1.0", end="end"):
          '''Apply the given tag to all text that matches the given pattern
  
          If 'regexp' is set to True, pattern will be treated as a regular
          expression.
          '''
          print(regex)
          start = self.index(start)
          end = self.index(end)
          self.mark_set("matchStart", start)
          self.mark_set("matchEnd", start)
          self.mark_set("searchLimit", end)
  
          count = tk.IntVar()
          while True:
              index = self.search(pattern, "matchEnd","searchLimit",
                                  count=count, regexp=regex)
              if index == "": break
              self.mark_set("matchStart", index)
              self.mark_set("matchEnd", "%s+%sc" % (index, count.get()))
              self.tag_add(tag, "matchStart", "matchEnd")
  
  class Tab:
      def __init__(self, parent, filename, parentwindow):
          self.fileName = "Untitled Document"
          self.content = ""
          self.previousContent = ""
          self.parentwindow = parentwindow
          self.language = "Python"
  
          self.row = "0"
          self.column = "0"
          self.startCol = 0
  
          self.parent = parent
          self.filename = filename
          self.tab1 = ttk.Frame(parent)
          self.text = CustomText(self.tab1, bd=0, font=("Tahoma", 9))  
  
          self.vsb = tk.Scrollbar(self.tab1, orient=tk.VERTICAL)
          self.text.configure(yscrollcommand=self.vsb.set)
          self.vsb.configure(command=self.text.yview)
  
          self.vsb.pack(side=tk.RIGHT, fill=tk.Y)
          self.text.pack(side="right", fill="both", expand=True)
  
          parent.add(self.tab1, text=filename)
  
          self.text.bind("&lt;KeyRelease&gt;", self.keypress)
          self.text.bind("&lt;Button-1&gt;", self.keypress)
  
          self.parent = parent
  
          self.configureTags()
  
      def configureTags(self):
          self.text.tag_configure("Token.Keyword", foreground="#CC7A00")
          self.text.tag_configure("Token.Keyword.Constant", foreground="#CC7A00")
          self.text.tag_configure("Token.Keyword.Declaration", foreground="#CC7A00")
          self.text.tag_configure("Token.Keyword.Namespace", foreground="#CC7A00")
          self.text.tag_configure("Token.Keyword.Pseudo", foreground="#CC7A00")
          self.text.tag_configure("Token.Keyword.Reserved", foreground="#CC7A00")
          self.text.tag_configure("Token.Keyword.Type", foreground="#CC7A00")
  
          self.text.tag_configure("Token.Name.Class", foreground="#003D99")
          self.text.tag_configure("Token.Name.Exception", foreground="#003D99")
          self.text.tag_configure("Token.Name.Function", foreground="#003D99")
  
          self.text.tag_configure("Token.Operator.Word", foreground="#CC7A00")
  
          self.text.tag_configure("Token.Comment", foreground="#B80000")
  
          self.text.tag_configure("Token.Literal.String", foreground="#248F24")
  
      def deafultHighlight(self, argument):
          self.content = self.text.get("1.0", tk.END)
          self.lines = self.content.split("\n")
  
          if (self.previousContent != self.content):
              self.row = self.text.index(tk.INSERT).split(".")[0]
              self.column = self.text.index(tk.INSERT).split(".")[1]
  
              self.text.mark_set("range_start", self.row + ".0")
              data = self.text.get(self.row + ".0", self.row + "." + str(len(self.lines[int(self.row) - 1])))
  
              for token, content in lex(data, PythonLexer()):
                  self.text.mark_set("range_end", "range_start + %dc" % len(content))
                  self.text.tag_add(str(token), "range_start", "range_end")
                  self.text.mark_set("range_start", "range_end")
  
          self.previousContent = self.text.get("1.0", tk.END)
  
      def highlight(self, argument):
          self.content = self.text.get("1.0", tk.END)
  
          if (self.previousContent != self.content):
              self.text.mark_set("range_start", "1.0")
              data = self.text.get("1.0", self.text.index(tk.INSERT))
  
              for token, content in lex(data, PythonLexer()):
                  self.text.mark_set("range_end", "range_start + %dc" % len(content))
                  self.text.tag_add(str(token), "range_start", "range_end")
                  self.text.mark_set("range_start", "range_end")
  
          self.previousContent = self.text.get("1.0", tk.END)
  
      def searchHighlight(self, term, color, regexOrNot):
          self.text.tag_configure("highlight", background=color)
          self.text.highlight_pattern(term, "highlight", regexOrNot)
  
      def individualHighlight(self, startPos, endPos, color):
          self.text.tag_configure("highlightedWord", background=color)
          self.text.tag_add("highlightedWord", startPos, endPos)
  
      def clearPreviousHighlight(self, startPos, endPos, color):
          self.text.tag_configure("clearHighlight", background=color)
          self.text.tag_add("clearHighlight", startPos, endPos)
  
      def clearAll(self, color):
          self.text.tag_delete("highlight")
          self.text.tag_delete("clearHighlight")
          self.text.tag_delete("highlightedWord")
  
      def getContent(self):
          return self.text.get(0.0, tk.END)
  
      def keypress(self, argument):
          self.deafultHighlight("argument")
  
      def replace(self, content):
          self.text.delete(1.0, tk.END)
          self.text.insert(1.0, content)
  
  class Arshi(tk.Frame):
      def __init__(self, *args, **kwargs):
          tk.Frame.__init__(self, *args, **kwargs)
          self.tabs = []
  
          self.notebook = ttk.Notebook(self)
          self.fileName = ""
          self.content = ""
  
          self.highlightColor = "#D2D2D2"
          self.standardSearchColor = "#ADDEAD"
  
          self.createtext()
          self.menubar()
  
          self.instance = 0
  
          self.bind_all("&lt;Control-f&gt;", self.search)
  
      def createtext(self):
          self.notebook.pack(fill=tk.BOTH, expand=True)
          t = Tab(self.notebook, "Untitled Document", self)
          self.tabs.append(t)
  
      def menubar(self):
          self.menu = tk.Menu(self)
          self.master.config(menu=self.menu)
  
          self.editMenu = tk.Menu(self.menu, font=("Tahoma", 9))
          self.editMenu.add_command(label="Find and Replace                    Ctrl+F", command=lambda: self.search("arg"))
          self.menu.add_cascade(label="Edit", menu=self.editMenu)
  
      def getColor(self):
          self.color = tkinter.colorchooser.askcolor(parent=self.searchMenu)[1]
          self.highlightLineEntry.insert(0, self.color)
          self.highlightColor = self.color
  
      def searchProtocol(self):
          self.instance = 0
  
          tabIndex = self.notebook.index(self.notebook.select())
          self.pos = '1.0'
          self.finalPos = '1.0'
          self.previousPos = self.pos
          self.previousFinalPos = self.finalPos
  
          self.tabs[tabIndex].clearAll("#FFFFFF")
  
          self.searchMenu.destroy()
  
      def search(self, arg):
          self.searchMenu = tk.Toplevel()
          self.searchMenu.title("Search and Replace")
          self.searchMenu.geometry("545x240")
          self.searchMenu.resizable(0, 0)
  
          self.searchDirection = tk.Label(self.searchMenu, text=" String to search:", anchor=tk.W, font=("Tahoma", 9))
          self.entry = tk.Entry(self.searchMenu, width=30, font=("Tahoma", 9))
  
          self.replaceDirection = tk.Label(self.searchMenu, text=" String to replace:", anchor=tk.W, font=("Tahoma", 9))
          self.replace = tk.Entry(self.searchMenu, width=30, font=("Tahoma", 9))
  
          self.searchOptions = tk.Label(self.searchMenu, text=" Search options:", anchor=tk.W, font=("Tahoma", 9))
  
          self.regex = tk.IntVar()
          self.regularExpression = tk.Checkbutton(self.searchMenu, text="Regex", variable=self.regex, anchor=tk.W, font=("Tahoma", 9))
  
          self.matchcase = tk.IntVar()
          self.matchCase = tk.Checkbutton(self.searchMenu, text="Match Case", variable=self.matchcase, anchor=tk.W, font=("Tahoma", 9))
  
          self.searchWay = tk.Label(self.searchMenu, text=" Search direction:", anchor = tk.W, font=("Tahoma", 9))
  
          self.direction = tk.IntVar()
          self.up = tk.Radiobutton(self.searchMenu, text="Up", variable=self.direction, value=1).place(x=175, y=75, width=140)
          self.down = tk.Radiobutton(self.searchMenu, text="Down", variable=self.direction, value=2).place(x=340, y=75, width=140)
  
          self.searchButton = tk.Button(self.searchMenu, text="Search", font=("Tahoma", 9), command=lambda: self.continueSearch(self.entry.get()))
  
          self.searchClose = tk.Button(self.searchMenu, text="Replace", font=("Tahoma", 9), command=lambda: self.replaceAll(self.entry.get(), self.replace.get()))
  
          self.searchRange = tk.Label(self.searchMenu, text=" Search range (line):", anchor = tk.W, font=("Tahoma", 9))
          self.rangeEntry = tk.Entry(self.searchMenu, width=30, font=("Tahoma", 9))
  
          self.highlightLine = tk.Label(self.searchMenu, text=" Search color (hex):", anchor=tk.W, font=("Tahoma", 9))
          self.highlightLineButton = tk.Button(self.searchMenu, text="Select", anchor=tk.W, font=("Tahoma", 9), command=self.getColor)
          self.highlightLineEntry = tk.Entry(self.searchMenu, width=30, font=("Tahoma", 9))
  
          self.occurenceLabel = tk.Label(self.searchMenu, text=" Search: {0} occurences, at occurence {1}".format("0", "0"), anchor=tk.CENTER, font=("Tahoma", 9))
  
          self.searchMenu.protocol("WM_DELETE_WINDOW", self.searchProtocol)
  
          self.searchDirection.place(x=0, y=0, width=200)
          self.replaceDirection.place(x=0, y=25, width=200)
          self.searchOptions.place(x=0, y=50, width=200)
          self.searchWay.place(x=0, y=75, width=200)
          self.searchRange.place(x=0, y=100, width=140)
          self.rangeEntry.place(x=220, y=100, width=325)
          self.highlightLine.place(x=0, y=125, width=145)
          self.highlightLineButton.place(x=145, y=125)
          self.highlightLineEntry.place(x=220, y=125, width=325)
          self.occurenceLabel.place(x =0, y=160)
          self.searchButton.place(x=20, y=195, width=200)
          self.searchClose.place(x=325, y=195, width=200)
  
          self.entry.place(x=220, y=0, width=325)
          self.replace.place(x=220, y=25, width=325)
          self.matchCase.place(x=220, y=50, width=140)
          self.regularExpression.place(x=375, y=50, width=140)
  
      def replaceAll(self, replaceTerm, newTerm):
          if len(replaceTerm) &gt; 0:
              tabIndex = self.notebook.index(self.notebook.select())
              self.content = self.tabs[tabIndex].getContent().replace(replaceTerm, newTerm)
              self.tabs[tabIndex].replace(self.content)
              self.tabs[tabIndex].highlight("argument")
  
      def continueSearch(self, term):
          self.regexIndex = self.regex.get()
          self.regexOrNot = False
  
  
          if self.regexIndex == 1:
              self.regexOrNot = True
  
          self.hex = self.highlightLineEntry.get()
          self.validHex = re.search(r'^#(?:[0-9a-fA-F]{3}){1,2}$', self.highlightColor)
  
          if len(self.hex) == 0:
              self.validHex = False
  
          if len(term) &gt; 0:
              tabIndex = self.notebook.index(self.notebook.select())
  
              if self.validHex:
                  self.tabs[tabIndex].searchHighlight(term, self.hex, self.regexOrNot)
              else:
                  self.tabs[tabIndex].searchHighlight(term, self.highlightColor, self.regexOrNot)
  
              numberOfInstances = self.tabs[tabIndex].text.get(0.0, tk.END).count(term)
  
              self.instance += 1
  
              if self.instance == 1:
                  if self.regexOrNot == False:
                      self.pos = self.tabs[tabIndex].text.search(term, '1.0')
                      self.finalPos = '{}+{}c'.format(self.pos, len(term))
                  else:
                      self.pos = self.tabs[tabIndex].text.search(term, '1.0', regexp=True)
                      self.finalPos = '{}+{}c'.format(self.pos, len(term))
  
                  self.tabs[tabIndex].individualHighlight(self.pos, self.finalPos, "#ADDEAD")
  
              elif self.instance &lt;= numberOfInstances:
                  self.previousPos = self.pos
                  self.previousFinalPos = self.finalPos
  
                  self.pos = self.finalPos
  
                  if self.regexOrNot == False:
                      self.pos = self.tabs[tabIndex].text.search(term, self.pos)
                      self.finalPos = '{}+{}c'.format(self.pos, len(term))
                  else:
                      self.pos = self.tabs[tabIndex].text.search(term, '1.0', regexp=True)
                      self.finalPos = '{}+{}c'.format(self.pos, len(term))
  
                  self.tabs[tabIndex].clearPreviousHighlight(self.previousPos, self.previousFinalPos, self.highlightColor)
                  self.tabs[tabIndex].individualHighlight(self.pos, self.finalPos, "#ADDEAD")
  
              self.occurenceLabel["text"] = " Search: {0} occurences, selecting occurence {1}".format(self.tabs[tabIndex].getContent().count(term), str(min(self.tabs[tabIndex].getContent().count(term), self.instance)))
  
  if __name__ == "__main__":
      root = tk.Tk()
      root.title("Arshi")
      root.geometry("1024x600")
      window = Arshi(root).pack(side="top", fill="both", expand=True)
      root.mainloop()
  </code></pre>