Skip to content

Instantly share code, notes, and snippets.

@aorzh
Created February 25, 2020 16:59
Show Gist options
  • Select an option

  • Save aorzh/8fc575be53d2ecac6f4be94cca9e127c to your computer and use it in GitHub Desktop.

Select an option

Save aorzh/8fc575be53d2ecac6f4be94cca9e127c to your computer and use it in GitHub Desktop.

Revisions

  1. aorzh created this gist Feb 25, 2020.
    18 changes: 18 additions & 0 deletions README.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    task description:

    please, write a function that receives
    1)path to file
    2) string to replace
    3) the new string to replace with
    4) in which line in the file to replace (if empty, then replace all)

    I assume new string should not be same with pattern
    Line number it's a real number (starts from 1). For example client see in text editor this number and pass it to func. I
    will switch it to index (as it's starts from 0)

    I wrapped it's to try/except with custom exception because in this way exceptions more clear and I can manage it.
    I added helper function for write lines because do not necessary write same code twice.

    There also possible to use fileinput standard library (https://docs.python.org/3/library/fileinput.html).
    But as multiple files wasn't in requirements I used open() as docs said "If you just want to read or write one file
    see open()."
    55 changes: 55 additions & 0 deletions test.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    import unittest
    from util import bulk_replace, UtilException


    class UtilTestCases(unittest.TestCase):
    def setUp(self):
    self.filepath = 'test_text'
    self.pattern = 'foo'
    self.replace_with = 'bar'

    def test_same_patterns(self):
    try:
    bulk_replace(filepath=self.filepath, pattern=self.pattern, replace_with='foo')
    except UtilException as e:
    self.assertEqual(e.__str__(), 'pattern and replace_with can not be same')

    def test_line(self):
    try:
    bulk_replace(filepath=self.filepath, pattern=self.pattern, replace_with=self.replace_with, line=999)
    except UtilException as e:
    self.assertEqual(e.__str__(), 'line not found')

    try:
    bulk_replace(filepath=self.filepath, pattern=self.pattern, replace_with=self.replace_with, line=-1)
    except UtilException as e:
    self.assertEqual(e.__str__(), 'line index should be gte 1')

    def test_replace_one_line(self):
    bulk_replace(filepath=self.filepath, pattern=self.pattern, replace_with=self.replace_with, line=1)
    file = open(self.filepath, 'r')
    line = file.readlines()
    file.close()

    self.assertEqual(line[0].strip('\n'), self.replace_with)
    # switch it back
    bulk_replace(filepath=self.filepath, pattern=self.replace_with, replace_with=self.pattern, line=1)

    def test_replace_all(self):
    file = open(self.filepath, 'r')
    old = file.readlines()
    file.close()
    bulk_replace(filepath=self.filepath, pattern=self.pattern, replace_with=self.replace_with)

    file = open(self.filepath, 'r')
    lines = file.readlines()
    self.assertTrue(self.pattern not in lines)

    # switch it back
    file = open(self.filepath, 'w')
    file.writelines(old)
    file.close()


    if __name__ == '__main__':
    unittest.main()
    5 changes: 5 additions & 0 deletions test_text
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    foo
    bar
    foo-bar
    bar-foo-bar
    foo-bar-bar
    48 changes: 48 additions & 0 deletions util.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,48 @@
    class UtilException(Exception):
    pass


    def bulk_replace(filepath, pattern, replace_with, line=None):
    """
    Function which open file, find necessary pattern and replace it with new fragment.
    :param filepath: Path to file
    :param pattern: String to replace
    :param replace_with: The new string to replace with
    :param line: In which line in the file to replace (if empty, then replace all)
    :return:
    """
    try:
    assert pattern != replace_with
    except AssertionError:
    raise UtilException('pattern and replace_with can not be same')

    with open(filepath, 'r') as f:
    text = f.readlines()
    f.close()
    if line: # assume we get line number, not index
    try:
    assert line >= 1
    try:
    # replace necessary text
    text[line-1] = text[line-1].replace(pattern, replace_with)
    _write_lines(filepath, text)
    except IndexError:
    raise UtilException('line not found')
    except AssertionError:
    raise UtilException('line index should be gte 1')
    else:
    # walk through all lines and replace necessary text
    lines = [line.replace(pattern, replace_with) for line in text]
    _write_lines(filepath, lines)


    def _write_lines(filepath, lines):
    """
    Helper function
    :param filepath: File path to open
    :param lines: list of lines
    :return:
    """
    with open(filepath, 'w') as f:
    f.writelines(lines)
    f.close()