#!/usr/bin/env python
"""
rotate.py -- A simple function for comparing whether a given string is
a rotation of another.
(c) 2012, James King
"""
__author__ = 'James King'
__email__ = 'james@agentultra.com'
import doctest
def split_string(s, separator_p, include_separator=False):
"""
Return a list of strings from 's' using the test function
'separator_p' as the delimiter.
'separater_p' is a function that takes a single character string
as its argument and should return a Boolean.
If include_separator is True, then include the delimiting
character in the word.
>>> split_string("the quick brown fox", lambda c: c.isspace())
['the', 'quick', 'brown', 'fox']
>>> split_string("the1quick2brown2fox", lambda c: c.isdigit())
['the', 'quick', 'brown', 'fox']
>>> split_string("the1quick2brown2fox", lambda c: c.isdigit(),
... include_separator=True)
['the', '1quick', '2brown', '2fox']
>>> split_string("ProgrammingPraxis", lambda c: c.isupper(),
... include_separator=True)
['Programming', 'Praxis']
"""
words = []
pivot = 0
for idx, char in enumerate(s):
if separator_p(char):
words.append(s[pivot:idx])
pivot = idx if include_separator else idx + 1
if pivot < len(s):
words.append(s[pivot:])
if include_separator:
# filter the special case where the first word includes the
# separator and we append an empty list to words. (ie:
# 'CamelCase')
return filter(lambda x: len(x), words)
else:
return words
def rotate(s1, s2, separator=lambda s: s.isupper(), include_sep=True):
"""
Return True if s1 is a rotation of s2.
'separator' is a function that takes one argument, a single
character string, which determines the word delimiter.
'include_sep' determines whether to include the delimiter
character in the words to be compared.
>>> rotate("ProgrammingPraxis", "PraxisProgramming")
True
>>> rotate("ProgrammingPraxis", "ProgrammingPrasix")
False
>>> rotate("AReallyInterestingExample", "ExampleInterestingReallyA")
True
>>> rotate("test1_test2", "test2_test1", separator=lambda c: c == '_',
... include_sep=False)
True
But if you include the separator:
>>> rotate("test1_test2", "test2_test1", separator=lambda c: c == '_')
False
Becase the word list will look like ['test1', '_test2'] and
['test2', '_test1'] for s1 and s2 respectively. A general rule of
thumb is to leave out the separator if it's not a part of the
words you want to check (ie: 'test1_test2' is bad, but 'CamelCase'
is good).
>>> rotate("asdasd", "asdasd")
True
>>> rotate("asdasd", "erferf")
False
If no separator is found, the function will treat the word list as
a single word and do what we expect it to.
"""
s1_words = split_string(s1, separator, include_separator=include_sep)
s2_words = split_string(s2, separator, include_separator=include_sep)
s2_words.reverse()
if s1_words == s2_words:
return True
else:
return False
if __name__ == '__main__':
doctest.testmod()