mirror of
https://github.com/jlu5/PyLink.git
synced 2024-12-26 12:43:09 +01:00
utils: add remove_range()
""" Removes a range string of (one-indexed) items from the list. Range strings are indices or ranges of them joined together with a ",": e.g. "5", "2", "2-10", "1,3,5-8" See test/test_utils.py for more complete examples. """
This commit is contained in:
parent
f8e3cfa346
commit
c919c523dc
@ -41,5 +41,94 @@ class UtilsTestCase(unittest.TestCase):
|
|||||||
"\x0305t\x030,1h\x0307,02e\x0308,06 \x0309,13q\x0303,15u\x0311,14i\x0310,05c\x0312,04k\x0302,07 \x0306,08b\x0313,09r\x0305,10o\x0304,12w\x0307,02n\x0308,06 \x0309,13f\x0303,15o\x0311,14x\x0310,05 \x0312,04j\x0302,07u\x0306,08m\x0313,09p\x0305,10s\x0304,12 \x0307,02o\x0308,06v\x0309,13e\x0303,15r\x0311,14 \x0310,05t\x0312,04h\x0302,07e\x0306,08 \x0313,09l\x0305,10a\x0304,12z\x0307,02y\x0308,06 \x0309,13d\x0303,15o\x0311,14g\x0f"),
|
"\x0305t\x030,1h\x0307,02e\x0308,06 \x0309,13q\x0303,15u\x0311,14i\x0310,05c\x0312,04k\x0302,07 \x0306,08b\x0313,09r\x0305,10o\x0304,12w\x0307,02n\x0308,06 \x0309,13f\x0303,15o\x0311,14x\x0310,05 \x0312,04j\x0302,07u\x0306,08m\x0313,09p\x0305,10s\x0304,12 \x0307,02o\x0308,06v\x0309,13e\x0303,15r\x0311,14 \x0310,05t\x0312,04h\x0302,07e\x0306,08 \x0313,09l\x0305,10a\x0304,12z\x0307,02y\x0308,06 \x0309,13d\x0303,15o\x0311,14g\x0f"),
|
||||||
"the quick brown fox jumps over the lazy dog")
|
"the quick brown fox jumps over the lazy dog")
|
||||||
|
|
||||||
|
def test_remove_range(self):
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"1", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[2,3,4,5,6,7,8,9])
|
||||||
|
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"2,4", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[1,3,5,6,7,8,9])
|
||||||
|
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"1-4", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[5,6,7,8,9])
|
||||||
|
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"1-3,7", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[4,5,6,8,9])
|
||||||
|
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"1-3,5-9", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[4])
|
||||||
|
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"1-2,3-5,6-9", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[])
|
||||||
|
|
||||||
|
# Anti-patterns, but should be legal
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"4,2", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[1,3,5,6,7,8,9])
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
"4,4,4", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[1,2,3,5,6,7,8,9])
|
||||||
|
|
||||||
|
# Empty subranges should be filtered away
|
||||||
|
self.assertEqual(utils.remove_range(
|
||||||
|
",2,,4,", [1,2,3,4,5,6,7,8,9]),
|
||||||
|
[1,3,5,6,7,8,9])
|
||||||
|
|
||||||
|
# Not enough items
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
utils.remove_range(
|
||||||
|
"5", ["abcd", "efgh"])
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
utils.remove_range(
|
||||||
|
"1-5", ["xyz", "cake"])
|
||||||
|
|
||||||
|
# Ranges going in reverse or invalid
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
utils.remove_range(
|
||||||
|
"5-2", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"2-2", [":)", ":D", "^_^"])
|
||||||
|
|
||||||
|
# 0th element
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
utils.remove_range(
|
||||||
|
"5,0", list(range(50)))
|
||||||
|
|
||||||
|
# List can't contain None
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
utils.remove_range(
|
||||||
|
"1-2", [None, "", 0, False])
|
||||||
|
|
||||||
|
# Malformed indices
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
utils.remove_range(
|
||||||
|
" ", ["some", "clever", "string"])
|
||||||
|
utils.remove_range(
|
||||||
|
" ,,, ", ["some", "clever", "string"])
|
||||||
|
utils.remove_range(
|
||||||
|
"a,b,c,1,2,3", ["some", "clever", "string"])
|
||||||
|
|
||||||
|
# Malformed ranges
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
utils.remove_range(
|
||||||
|
"1,2-", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"-", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"1-2-3", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"-1-2", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"3--", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"--5", [":)", ":D", "^_^"])
|
||||||
|
utils.remove_range(
|
||||||
|
"-3--5", ["we", "love", "emotes"])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
51
utils.py
51
utils.py
@ -735,3 +735,54 @@ def strip_irc_formatting(text):
|
|||||||
for char in _irc_formatting_chars:
|
for char in _irc_formatting_chars:
|
||||||
text = text.replace(char, '')
|
text = text.replace(char, '')
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
_subrange_re = re.compile(r'(?P<start>(\d+))-(?P<end>(\d+))')
|
||||||
|
def remove_range(rangestr, mylist):
|
||||||
|
"""
|
||||||
|
Removes a range string of (one-indexed) items from the list.
|
||||||
|
Range strings are indices or ranges of them joined together with a ",":
|
||||||
|
e.g. "5", "2", "2-10", "1,3,5-8"
|
||||||
|
|
||||||
|
See test/test_utils.py for more complete examples.
|
||||||
|
"""
|
||||||
|
if None in mylist:
|
||||||
|
raise ValueError("mylist must not contain None!")
|
||||||
|
|
||||||
|
# Split and filter out empty subranges
|
||||||
|
ranges = filter(None, rangestr.split(','))
|
||||||
|
if not ranges:
|
||||||
|
raise ValueError("Invalid range string %r" % rangestr)
|
||||||
|
|
||||||
|
for subrange in ranges:
|
||||||
|
match = _subrange_re.match(subrange)
|
||||||
|
if match:
|
||||||
|
start = int(match.group('start'))
|
||||||
|
end = int(match.group('end'))
|
||||||
|
|
||||||
|
if end <= start:
|
||||||
|
raise ValueError("Range start (%d) is <= end (%d) in range string %r" %
|
||||||
|
(start, end, rangestr))
|
||||||
|
elif 0 in (end, start):
|
||||||
|
raise ValueError("Got range index 0 in range string %r, this function is one-indexed" %
|
||||||
|
rangestr)
|
||||||
|
|
||||||
|
# For our purposes, make sure the start and end are within the list
|
||||||
|
mylist[start-1], mylist[end-1]
|
||||||
|
|
||||||
|
# Replace the entire range with None's
|
||||||
|
log.debug('utils.remove_range: removing items from %s to %s: %s', start, end, mylist[start-1:end])
|
||||||
|
mylist[start-1:end] = [None] * (end-(start-1))
|
||||||
|
|
||||||
|
elif subrange in string.digits:
|
||||||
|
index = int(subrange)
|
||||||
|
if index == 0:
|
||||||
|
raise ValueError("Got index 0 in range string %r, this function is one-indexed" %
|
||||||
|
rangestr)
|
||||||
|
log.debug('utils.remove_range: removing item %s: %s', index, mylist[index-1])
|
||||||
|
mylist[index-1] = None
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError("Got invalid subrange %r in range string %r" %
|
||||||
|
(subrange, rangestr))
|
||||||
|
|
||||||
|
return list(filter(lambda x: x is not None, mylist))
|
||||||
|
Loading…
Reference in New Issue
Block a user