Modify usage of re.match to fit re.fullmatch or re.search.

re.match features an implicit left anchor, which can be surprising.

re.fullmatch features implicit anchors on both sides, but is aptly named
and unsurprising.

re.search has no such implicit anchors, which ought to be the default
even if a single anchor is needed.
This commit is contained in:
George Edward Bulmer 2017-12-11 21:32:55 +00:00
parent 481dec067d
commit 747a9bc5b6
10 changed files with 16 additions and 15 deletions

View File

@ -180,7 +180,7 @@ def transform_path(path):
path = utils.expand_windows_drive(path) path = utils.expand_windows_drive(path)
# Drive dependent working directories are not supported, e.g. # Drive dependent working directories are not supported, e.g.
# E:filename is invalid # E:filename is invalid
if re.match(r'[A-Z]:[^\\]', path, re.IGNORECASE): if re.fullmatch(r'[A-Z]:[^\\]', path, re.IGNORECASE):
return None return None
# Paths like COM1, ... # Paths like COM1, ...
# See https://github.com/qutebrowser/qutebrowser/issues/82 # See https://github.com/qutebrowser/qutebrowser/issues/82

View File

@ -30,7 +30,7 @@ from qutebrowser.utils import log
def version(filename): def version(filename):
"""Extract the version number from the dictionary file name.""" """Extract the version number from the dictionary file name."""
version_re = re.compile(r".+-(?P<version>[0-9]+-[0-9]+?)\.bdic") version_re = re.compile(r".+-(?P<version>[0-9]+-[0-9]+?)\.bdic")
match = version_re.match(filename) match = version_re.fullmatch(filename)
if match is None: if match is None:
raise ValueError('the given dictionary file name is malformed: {}' raise ValueError('the given dictionary file name is malformed: {}'
.format(filename)) .format(filename))

View File

@ -963,7 +963,7 @@ class Font(BaseType):
# Gets set when the config is initialized. # Gets set when the config is initialized.
monospace_fonts = None monospace_fonts = None
font_regex = re.compile(r""" font_regex = re.compile(r"""
^( (
( (
# style # style
(?P<style>normal|italic|oblique) | (?P<style>normal|italic|oblique) |
@ -976,14 +976,14 @@ class Font(BaseType):
(?P<size>[0-9]+((\.[0-9]+)?[pP][tT]|[pP][xX])) (?P<size>[0-9]+((\.[0-9]+)?[pP][tT]|[pP][xX]))
)\ # size/weight/style are space-separated )\ # size/weight/style are space-separated
)* # 0-inf size/weight/style tags )* # 0-inf size/weight/style tags
(?P<family>.+)$ # mandatory font family""", re.VERBOSE) (?P<family>.+) # mandatory font family""", re.VERBOSE)
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if not value:
return None return None
if not self.font_regex.match(value): # pragma: no cover if not self.font_regex.fullmatch(value): # pragma: no cover
# This should never happen, as the regex always matches everything # This should never happen, as the regex always matches everything
# as family. # as family.
raise configexc.ValidationError(value, "must be a valid font") raise configexc.ValidationError(value, "must be a valid font")
@ -1002,7 +1002,7 @@ class FontFamily(Font):
if not value: if not value:
return None return None
match = self.font_regex.match(value) match = self.font_regex.fullmatch(value)
if not match: # pragma: no cover if not match: # pragma: no cover
# This should never happen, as the regex always matches everything # This should never happen, as the regex always matches everything
# as family. # as family.
@ -1039,7 +1039,7 @@ class QtFont(Font):
font.setStyle(QFont.StyleNormal) font.setStyle(QFont.StyleNormal)
font.setWeight(QFont.Normal) font.setWeight(QFont.Normal)
match = self.font_regex.match(value) match = self.font_regex.fullmatch(value)
if not match: # pragma: no cover if not match: # pragma: no cover
# This should never happen, as the regex always matches everything # This should never happen, as the regex always matches everything
# as family. # as family.

View File

@ -150,7 +150,8 @@ class BaseKeyParser(QObject):
A (count, command) tuple. A (count, command) tuple.
""" """
if self._supports_count: if self._supports_count:
(countstr, cmd_input) = re.match(r'^(\d*)(.*)', keystring).groups() (countstr, cmd_input) = re.fullmatch(r'(\d*)(.*)',
keystring).groups()
count = int(countstr) if countstr else None count = int(countstr) if countstr else None
if count == 0 and not cmd_input: if count == 0 and not cmd_input:
cmd_input = keystring cmd_input = keystring

View File

@ -62,7 +62,7 @@ def parse_fatal_stacktrace(text):
r'(Current )?[Tt]hread [^ ]* \(most recent call first\): *', r'(Current )?[Tt]hread [^ ]* \(most recent call first\): *',
r' File ".*", line \d+ in (?P<func>.*)', r' File ".*", line \d+ in (?P<func>.*)',
] ]
m = re.match('\n'.join(lines), text) m = re.search('\n'.join(lines), text)
if m is None: if m is None:
# We got some invalid text. # We got some invalid text.
return ('', '') return ('', '')

View File

@ -87,7 +87,7 @@ class KeyHintView(QLabel):
Args: Args:
prefix: The current partial keystring. prefix: The current partial keystring.
""" """
countstr, prefix = re.match(r'^(\d*)(.*)', prefix).groups() countstr, prefix = re.fullmatch(r'(\d*)(.*)', prefix).groups()
if not prefix: if not prefix:
self._show_timer.stop() self._show_timer.stop()
self.hide() self.hide()

View File

@ -184,7 +184,7 @@ def signal_name(sig):
Return: Return:
The cleaned up signal name. The cleaned up signal name.
""" """
m = re.match(r'[0-9]+(.*)\(.*\)', sig.signal) m = re.fullmatch(r'[0-9]+(.*)\(.*\)', sig.signal)
return m.group(1) return m.group(1)

View File

@ -156,7 +156,7 @@ class DocstringParser:
def _parse_arg_inside(self, line): def _parse_arg_inside(self, line):
"""Parse subsequent argument lines.""" """Parse subsequent argument lines."""
argname = self._cur_arg_name argname = self._cur_arg_name
if re.match(r'^[A-Z][a-z]+:$', line): if re.fullmatch(r'[A-Z][a-z]+:', line):
if not self.arg_descs[argname][-1].strip(): if not self.arg_descs[argname][-1].strip():
self.arg_descs[argname] = self.arg_descs[argname][:-1] self.arg_descs[argname] = self.arg_descs[argname][:-1]
return True return True

View File

@ -306,7 +306,7 @@ def qurl_from_user_input(urlstr):
""" """
# First we try very liberally to separate something like an IPv6 from the # First we try very liberally to separate something like an IPv6 from the
# rest (e.g. path info or parameters) # rest (e.g. path info or parameters)
match = re.match(r'\[?([0-9a-fA-F:.]+)\]?(.*)', urlstr.strip()) match = re.fullmatch(r'\[?([0-9a-fA-F:.]+)\]?(.*)', urlstr.strip())
if match: if match:
ipstr, rest = match.groups() ipstr, rest = match.groups()
else: else:
@ -571,7 +571,7 @@ def incdec_number(url, incdec, count=1, segments=None):
continue continue
# Get the last number in a string # Get the last number in a string
match = re.match(r'(.*\D|^)(0*)(\d+)(.*)', getter()) match = re.fullmatch(r'(.*\D|^)(0*)(\d+)(.*)', getter())
if not match: if not match:
continue continue

View File

@ -869,7 +869,7 @@ def expand_windows_drive(path):
# E:\. The correct way to specifify drive E: is "E:\", but most users # E:\. The correct way to specifify drive E: is "E:\", but most users
# probably don't use the "multiple working directories" feature and expect # probably don't use the "multiple working directories" feature and expect
# "E:" and "E:\" to be equal. # "E:" and "E:\" to be equal.
if re.match(r'[A-Z]:$', path, re.IGNORECASE): if re.fullmatch(r'[A-Z]:', path, re.IGNORECASE):
return path + "\\" return path + "\\"
else: else:
return path return path