# Common Lisp/Advanced topics/CLOS/Example 1

Let's say we have a file that contains some subtitles to a movie, in the .srt format, for example:
But these subtitles are no good for you, because your version of the movie for some reason contains a 10.532 second pause in the beginning. It's impossible change all timestamps manually, and let's assume there's no tool that would do it for us. So we have to code a script in Common Lisp (what else). Let's start now!
The class of objects we will be working with is a set of timestamps. We need to be able to find them in a file, to add them together, and to insert them back.
display method would return a textual representation of a srt-time object. normalise is a helper function, which fixes all "overflows" of slots (there can't be more than 60 seconds and so on). make-srt-time is a wrapper around make-instance which allows easier creation of srt-time objects.
Now, we write two methods for adding time.
Adding a second way to add times doesn't look like much. But consider that every function that calls add may pass integer for second argument instead of srt-time. As we will see later, this extension of functionality propagates to upper layers of our program, including the function that's intended to be called by the user.
Now let's think about the second part of our task. Given a text string we must replace all instances of timestamps with modified timestamps. Fortunately, CL-PPCRE can do exactly that thing. We just need to find a fitting regular expression. Regexes aren't a topic of this Wikibook, but if you're not familiar with them, there are many good sites for learning this concept. I'll just write it down: "([0-9]{2,}):([0-9]{2}):([0-9]{2}),([0-9]{3})". At least try to figure how it corresponds to one specific timestamp, say 00:00:44,132. Note that the things that matched a part of regular expression between "(" and ")" are remembered by CL-PPCRE and we will use that fact. For now, let's generate a scanner that corresponds to that regular expression:
This scanner is actually a compiled function, but it's not necessary to know implementation details, if everything works like intended. The next step is to use this scanner to find and replace some substrings of a string:
The function just takes an arbitrary string and arbitrary function and uses this function to transform all timestamps that scanner *find-time* finds in that string. Now we'll write a function that feeds the right function to modify-times.
Now wasn't that fun? We construct the needed function at runtime, since we don't know yet how much time the user wants to add! regex-replace-all will call adder with 5 arguments. The first argument, match is for whole match - we don't need it. What we need is the parts (those surrounded by brackets). These correspond to hours, minutes, seconds and milliseconds. We convert them from strings to integers with parse-integer. Then a srt-time object is produced from these numbers, then delta is added to it (note that delta could be either srt-time or integer, we don't know, and we don't care). Then the result is converted back into string using display method. That's what CL-PPCRE wanted from that function, and we can now forget about CL-PPCRE and concentrate on other things.
The next function, mapline would slice a file into lines, feed these lines to some function and print these lines into output file.
Don't you like with-open-file? Concise and clean.
And now, the final function, that would combine the power of mapline and modify-times:
Now, why is this example filed under CLOS? Well, it shows why CLOS is good. It makes your programs very scalable. Consider that you need to add the functionality so that delay could be float number of seconds. Just write an appropriate add method. I'm leaving it as an exercise.