无法在Tkinter Text Widget中搜索正则表达式

时间:2015-08-20 23:23:35

标签: python regex tkinter

我正在尝试为我的文本编辑器开发Find and Replace。不幸的是regex似乎不起作用。这很奇怪,因为我在Python中使用Text搜索搜索regex窗口小部件。我怀疑问题在于正则表达式的错误长度。

我收到以下错误:

_tkinter.TclError: bad text index ""

以下是我的Python代码:

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 <<Change>> -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("<KeyRelease>", self.keypress)
        self.text.bind("<Button-1>", 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("<Control-f>", 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) > 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) > 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 <= 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()

1 个答案:

答案 0 :(得分:0)

尝试查看How to use a regular expression in Tkinter text search method?。问题可能在于您使用Text小部件的text.search功能

的方式