From 80e57fb21b76fb3aa78c327d2d8381b5014d5642 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 21 Dec 1997 07:05:32 +0000 Subject: Converted to use re instead of regex; version 0.9.0. --- Tools/faqwiz/README | 16 ++++++++-- Tools/faqwiz/faqconf.py | 12 ++++---- Tools/faqwiz/faqwiz.py | 79 ++++++++++++++++++++----------------------------- 3 files changed, 52 insertions(+), 55 deletions(-) diff --git a/Tools/faqwiz/README b/Tools/faqwiz/README index aca785e..c76077f 100644 --- a/Tools/faqwiz/README +++ b/Tools/faqwiz/README @@ -2,8 +2,8 @@ FAQ Wizard ---------- Author: Guido van Rossum -Version: 0.8.4 -Date: 16 December 1997 +Version: 0.9.0 +Date: 21 December 1997 This is a CGI program that maintains a user-editable FAQ. It uses RCS @@ -22,6 +22,17 @@ faqwiz.py main module, lives in same directory as FAQ entry files faqconf.py main configuration module faqcust.py additional local customization module (optional) + +What's New? +----------- + +Version 0.9.0 uses the re module (Perl style regular expressions) for +all its regular expression needs, instead of the regex and regsub +modules (Emacs style). This affects the syntax for regular +expressions entered by the user as search strings (with "regular +expression" checked), hence the version number jump. + + Setup Information ----------------- @@ -76,6 +87,7 @@ file faq01.001.htp,v in the RCS subdirectory. You can now exercise the other FAQ wizard features (search, index, whole FAQ, what's new, roulette, and so on). + Maintaining Multiple FAQs ------------------------- diff --git a/Tools/faqwiz/faqconf.py b/Tools/faqwiz/faqconf.py index 1fd4672..e1e6e39 100644 --- a/Tools/faqwiz/faqconf.py +++ b/Tools/faqwiz/faqconf.py @@ -49,7 +49,7 @@ entries marked with * were changed within the last 7 days.) # Version -- don't change unless you edit faqwiz.py -WIZVERSION = "0.8.4" # FAQ Wizard version +WIZVERSION = "0.9.0" # FAQ Wizard version # This parameter is normally overwritten with a dynamic value @@ -58,12 +58,12 @@ import os, sys FAQCGI = os.path.basename(sys.argv[0]) or FAQCGI del os, sys -# Regular expression to recognize FAQ entry files: group(1) should be -# the section number, group(2) should be the question number. Both -# should be fixed width so simple-minded sorting yields the right -# order. +# Perl (re module) style regular expression to recognize FAQ entry +# files: group(1) should be the section number, group(2) should be the +# question number. Both should be fixed width so simple-minded +# sorting yields the right order. -OKFILENAME = "^faq\([0-9][0-9]\)\.\([0-9][0-9][0-9]\)\.htp$" +OKFILENAME = r"^faq(\d\d)\.(\d\d\d)\.htp$" # Format to construct a FAQ entry file name diff --git a/Tools/faqwiz/faqwiz.py b/Tools/faqwiz/faqwiz.py index 14c4b30..6912cec 100644 --- a/Tools/faqwiz/faqwiz.py +++ b/Tools/faqwiz/faqwiz.py @@ -11,7 +11,7 @@ The actual script to place in cgi-bin is faqw.py. """ -import sys, string, time, os, stat, regex, cgi, faqconf +import sys, string, time, os, stat, re, cgi, faqconf from faqconf import * # This imports all uppercase names now = time.time() @@ -32,21 +32,15 @@ class NoSuchFile(FileError): FileError.__init__(self, file) self.why = why -def replace(s, old, new): - try: - return string.replace(s, old, new) - except AttributeError: - return string.join(string.split(s, old), new) - def escape(s): - s = replace(s, '&', '&') - s = replace(s, '<', '<') - s = replace(s, '>', '>') + s = string.replace(s, '&', '&') + s = string.replace(s, '<', '<') + s = string.replace(s, '>', '>') return s def escapeq(s): s = escape(s) - s = replace(s, '"', '"') + s = string.replace(s, '"', '"') return s def _interpolate(format, args, kw): @@ -73,20 +67,20 @@ translate_prog = None def translate(text, pre=0): global translate_prog if not translate_prog: - url = '\(http\|ftp\|https\)://[^ \t\r\n]*' - email = '\<[-a-zA-Z0-9._]+@[-a-zA-Z0-9._]+' - translate_prog = prog = regex.compile(url + '\|' + email) + translate_prog = prog = re.compile( + r'\b(http|ftp|https)://\S+(\b|/)|\b[-.\w]+@[-.\w]+') else: prog = translate_prog i = 0 list = [] while 1: - j = prog.search(text, i) - if j < 0: + m = prog.search(text, i) + if not m: break + j = m.start() list.append(escape(text[i:j])) i = j - url = prog.group(0) + url = m.group(0) while url[-1] in '();:,.?\'"<>': url = url[:-1] i = i + len(url) @@ -103,26 +97,19 @@ def translate(text, pre=0): list.append(escape(text[i:j])) return string.join(list, '') -emphasize_prog = None - def emphasize(line): - global emphasize_prog - import regsub - if not emphasize_prog: - pat = '\*\([a-zA-Z]+\)\*' - emphasize_prog = regex.compile(pat) - return regsub.gsub(emphasize_prog, '\\1', line) + return re.sub(r'\*([a-zA-Z]+)\*', r'\1', line) revparse_prog = None def revparse(rev): global revparse_prog if not revparse_prog: - revparse_prog = regex.compile( - '^\([1-9][0-9]?[0-9]?\)\.\([1-9][0-9]?[0-9]?[0-9]?\)$') - if revparse_prog.match(rev) < 0: + revparse_prog = re.compile(r'^(\d{1,3})\.(\d{1-4})$') + m = revparse_prog.match(rev) + if not m: return None - [major, minor] = map(string.atoi, revparse_prog.group(1, 2)) + [major, minor] = map(string.atoi, m.group(1, 2)) return major, minor def load_cookies(): @@ -315,7 +302,7 @@ class FaqDir: entryclass = FaqEntry - __okprog = regex.compile(OKFILENAME) + __okprog = re.compile(OKFILENAME) def __init__(self, dir=os.curdir): self.__dir = dir @@ -327,17 +314,18 @@ class FaqDir: self.__files = files = [] okprog = self.__okprog for file in os.listdir(self.__dir): - if okprog.match(file) >= 0: + if self.__okprog.match(file): files.append(file) files.sort() def good(self, file): - return self.__okprog.match(file) >= 0 + return self.__okprog.match(file) def parse(self, file): - if not self.good(file): + m = self.good(file) + if not m: return None - sec, num = self.__okprog.group(1, 2) + sec, num = m.group(1, 2) return string.atoi(sec), string.atoi(num) def list(self): @@ -426,31 +414,29 @@ class FaqWizard: self.error("Empty query string!") return if self.ui.querytype == 'simple': - for c in '\\.[]?+^$*': - if c in query: - query = replace(query, c, '\\'+c) + query = re.escape(query) queries = [query] elif self.ui.querytype in ('anykeywords', 'allkeywords'): - import regsub - words = string.split(regsub.gsub('[^a-zA-Z0-9]+', ' ', query)) + words = filter(None, re.split('\W+', query)) if not words: self.error("No keywords specified!") return - words = map(lambda w: '\<%s\>' % w, words) + words = map(lambda w: r'\b%s\b' % w, words) if self.ui.querytype[:3] == 'any': - queries = [string.join(words, '\|')] + queries = [string.join(words, '|')] else: + # Each of the individual queries must match queries = words else: - # Default to regex + # Default to regular expression queries = [query] self.prologue(T_SEARCH) progs = [] for query in queries: if self.ui.casefold == 'no': - p = regex.compile(query) + p = re.compile(query) else: - p = regex.compile(query, regex.casefold) + p = re.compile(query, re.IGNORECASE) progs.append(p) hits = [] for file in self.dir.list(): @@ -459,7 +445,7 @@ class FaqWizard: except FileError: constants for p in progs: - if p.search(entry.title) < 0 and p.search(entry.body) < 0: + if not p.search(entry.title) and not p.search(entry.body): break else: hits.append(file) @@ -777,8 +763,7 @@ class FaqWizard: file = entry.file # Normalize line endings in body if '\r' in self.ui.body: - import regsub - self.ui.body = regsub.gsub('\r\n?', '\n', self.ui.body) + self.ui.body = re.sub('\r\n?', '\n', self.ui.body) # Normalize whitespace in title self.ui.title = string.join(string.split(self.ui.title)) # Check that there were any changes -- cgit v0.12