remove_prefix and remove_suffix functions If the prefix/suffix does not match the beginning or the end of a string, then, depending on how I call these functions, they should either raise an exception or return the original text unmodified.

I am using these inside of a simple script for now, so there was no need to make these member functions of some class. I am hoping to find a way to simplify the logic, extract any common code into private function(s), improve the code style (although I think there are several different standards).

def remove_prefix(text, prefix, raise_if_no_match=True):
    exc_msg = 'Text "{}" does not start with a prefix "{}".'.format(text, prefix)
    if not prefix or not text:
        if not raise_if_no_match:
            return text
        if len(prefix) == len(text):
            return ''
        raise ValueError(exc_msg)
    if text.startswith(prefix):
        return text[len(prefix):]
    if raise_if_no_match:
        raise ValueError(exc_msg)
    return text

def remove_suffix(text, suffix, raise_if_no_match=True):
    exc_msg = 'Text "{}" does not end with a suffix "{}".'.format(text, suffix)
    if not suffix or not text:
        if not raise_if_no_match:
            return text
        if len(suffix) == len(text):
            return ''
        raise ValueError(exc_msg)
    if text.endswith(suffix):
        return text[:-len(suffix):]
    if raise_if_no_match:
        raise ValueError(exc_msg)
    return text

print remove_prefix('Hello, World', 'Hello, ')
# ValueError: Text "Hello, World" does not start with a prefix "Hello, Hello".
#print remove_prefix('Hello, World', 'Hello, Hello')
print remove_prefix('Hello, World', 'Hello, Hello', raise_if_no_match=False)

print remove_suffix('I am singing in the rain', ' in the rain')
# ValueError: Text "I am singing in the rain" does not end with a suffix "swinging in the rain".
#print remove_suffix('I am singing in the rain', 'swinging in the rain')
print remove_suffix('I am singing in the rain', 'swinging in the rain', raise_if_no_match=False)


Output:




World
Hello, World
I am singing
I am singing in the rain
Firstly I would say turn your print statements into a test. That way you can change the implementation with confidence that you have not broken anything.

Here is what those debug prints are as a test:

class TestRemove(unittest.TestCase):

    def test_remove_prefix(self):
        hello = 'Hello, World'
        value = remove_prefix(hello, 'Hello, ')
        self.assertEqual(value, 'World')
        value = remove_prefix(hello, 'Hello, Hello', raise_if_no_match=False)
        self.assertEqual(value, hello)
        self.assertRaises(ValueError, remove_prefix, hello, 'Hello, Hello')

    def test_remove_suffix(self):
        singing = 'I am singing in the rain'
        value = remove_suffix(singing, ' in the rain')
        self.assertEqual(value, 'I am singing')
        value = remove_suffix(singing, 'swinging in the rain', raise_if_no_match=False)
        self.assertEqual(value, singing)
        self.assertRaises(ValueError, remove_suffix, singing, 'swinging in the rain')


I think you should be using the the built in string operations which can be found here. Namely startswith(), endswith(), spilt() and rsplit().

You can also reassign variable names to give a more clear flow through the function. Here is my version of remove_prefix().

def remove_prefix(text, prefix, raise_if_no_match=True):
    if (text.startswith(prefix)):
        text = text.split(prefix, 1)[1]
    else:
        if (raise_if_no_match):
            msg_fmt = 'Text "{}" does not end with a prefix "{}".'
            raise ValueError(msg_fmt.format(text, prefix))
    return text


From that I'm sure you can change remove_suffix().

Also I would add docstrings to the functions so the arguments and exceptions raised are documented.