• Coding
  • Exercise - Text Processing and More

This company we're dealing with, that's handling our phone fees, is sending us some reports on our employees' personal calls. The bad part of the story is that their programmers are inept, and they couldn't do anything better than the pathological format they send the data in. The programmers are now dead (shot out of frustration by their boss), while the handling company doesn't have the resources to comprehend their existing code to update it to something more sane.

Enough introductions. The report should contain rows of the following fields:
- T: time (e.g. 10PM, 12AM, 1PM, 8PM)
- D: duration (e.g. 12sec, 894sec, 2000sec, ...)
- N: number (e.g. +71231888, +70929112, ..)
- Y: type (only one of these: SMS, WAP, PHONECALL)

The thing is, when the type is WAP, the phone number will not be included.
11PM
12PM
9AM
11AM
20sec
30sec
10sec
0sec
+70702211
+70703311
+70112111
PHONECALL
PHONECALL
WAP
SMS
This should be interpretted as:
T1
T2
T3
T4
D1
D2
D3
D4
N1
N2
N4
Y1
Y2
Y3
Y4
The purpose of this exercise is to reorganize the data so that it looks like this
T1 D1 N1 Y1
T2 D2 N2 Y2
T3 D3 N/A Y3
T4 D4 N4 Y4
Sounds more like a job description than an exercise :)
You're the newbie here, take your place. If you can check the profile history, you'd see I am posting these stuff like for a while now.

This is an insult, I can't take it lightly.
Wow, pulling seniority on me!
Anyways, I was just saying that it "sounded" like a real case scenario. Moreover, we are not in the army, and you don't get to order me around.
The newbie part is alluding to your ignorance to our practices (the exercises I am trying to resurrect), not to the fact that I am a senior here by any measure. It's just not really acceptable of you coming into a well practiced thing we do here and suggest insulting things like that.
We're not the army, but we do usually have a sense of respect for each other here, and some things are just unacceptable.
lol arithma, take it easy :)
and MSD, read before you post. it might sound like one, but it's not. arithma wouldn't need much to finish the exercise.
Interesting exercise, pretty much straight forward tho.
Forget I even said anything, don't wanna make a deal out of it.
So let's call the quarrel off, and here is a solution in case anyone is interested (C#):
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        private static List<string> _TimeList = new List<string>();
        private static List<string> _DurationList = new List<string>();
        private static List<string> _NumberList = new List<string>();
        private static List<string> _TypeList = new List<string>();
        private static string _Input =
@"11PM
12PM
9AM
11AM
20sec
30sec
10sec
0sec
+70702211
+70703311
+70112111
PHONECALL
PHONECALL
WAP
SMS";
        private static string ParseInput()
        {
            foreach (string s in _Input.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                if (s.EndsWith("PM") || s.EndsWith("AM"))
                    _TimeList.Add(s);
                else if (s.EndsWith("sec"))
                    _DurationList.Add(s);
                else if (s[0] == '+')
                    _NumberList.Add(s);
                else
                {
                    if (s == "WAP")
                        _NumberList.Insert(_TypeList.Count - 1, "N/A");
                    _TypeList.Add(s);
                }
            }
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < _TypeList.Count; i++)
                sb.AppendFormat("{0}\t{1}\t{2}\t{3}\n", _TimeList[i], _DurationList[i], _NumberList[i], _TypeList[i]);
            return sb.ToString();
        }
        static void Main(string[] args)
        {
            Console.Write(ParseInput());
        }

    }
}
Here is a more performant solution:
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        private static List<string> _TimeList = new List<string>();
        private static List<string> _DurationList = new List<string>();
        private static List<string> _NumberList = new List<string>();
        private static List<string> _TypeList = new List<string>();
        private static string _Input =
@"11PM
12PM
9AM
11AM
20sec
30sec
10sec
0sec
+70702211
+70703311
+70112111
PHONECALL
PHONECALL
WAP
SMS";

        private static string GetNextWord(string input, ref int index)
        {
            string buffer = string.Empty;
            while (index < input.Length && input[index] != '\r' && input[index] != '\n')
            {
                buffer += input[index++];
            }
            index++;
            if (index < input.Length && input[index] == '\n')
                index++;
            return buffer;
        }
        private static string ParseInput()
        {
            for (int index = 0; index < _Input.Length;)
            {
                string s = GetNextWord(_Input, ref index);
                if (s.EndsWith("PM") || s.EndsWith("AM"))
                    _TimeList.Add(s);
                else if (s.EndsWith("sec"))
                    _DurationList.Add(s);
                else if (s[0] == '+')
                    _NumberList.Add(s);
                else
                {
                    if (s == "WAP")
                        _NumberList.Insert(_TypeList.Count - 1, "N/A");
                    _TypeList.Add(s);
                }
            }
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < _TypeList.Count; i++)
                sb.AppendFormat("{0}\t{1}\t{2}\t{3}\n", _TimeList[i], _DurationList[i], _NumberList[i], _TypeList[i]);
            return sb.ToString();
        }
        static void Main(string[] args)
        {
            Console.Write(ParseInput());
            Console.Read();
        }
    }
}
@Padre: Don't worry I didn't get out of my temper. Thanks for the backing up :)
@MSD: We're very cool. Thanks for having interest in this exercise.
Though I'd like to warn to a common off-by-one error. The insert should have inserted into TypeList.Count.
Yup, corrected:
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        private static List<string> _TimeList = new List<string>();
        private static List<string> _DurationList = new List<string>();
        private static List<string> _NumberList = new List<string>();
        private static List<string> _TypeList = new List<string>();
        private static string _Input =
@"11PM
12PM
9AM
11AM
20sec
30sec
10sec
0sec
+70702211
+70703311
+70112111
PHONECALL
PHONECALL
WAP
SMS";

        private static string GetNextWord(string input, ref int index)
        {
            string buffer = string.Empty;
            while (index < input.Length && input[index] != '\r' && input[index] != '\n')
            {
                buffer += input[index++];
            }
            index++;
            if (index < input.Length && input[index] == '\n')
                index++;
            return buffer;
        }
        private static string ParseInput()
        {
            for (int index = 0; index < _Input.Length;)
            {
                string s = GetNextWord(_Input, ref index);
                if (s.EndsWith("PM") || s.EndsWith("AM"))
                    _TimeList.Add(s);
                else if (s.EndsWith("sec"))
                    _DurationList.Add(s);
                else if (s[0] == '+')
                    _NumberList.Add(s);
                else
                {
                    if (s == "WAP")
                        _NumberList.Insert(_TypeList.Count, "N/A");
                    _TypeList.Add(s);
                }
            }
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < _TypeList.Count; i++)
                sb.AppendFormat("{0}\t{1}\t{2}\t{3}\n", _TimeList[i], _DurationList[i], _NumberList[i], _TypeList[i]);
            return sb.ToString();
        }
        static void Main(string[] args)
        {
            Console.Write(ParseInput());
            Console.Read();
        }
    }
}
#!/usr/bin/python

class PlanHandler:

    TList = []
    DList = []
    NList = []
    YList = []
    plan = []

    def __init__(self, filename):
        f = open('input', 'r')
        for line in f:
            if line.find("AM") != -1: 
                self.TList.append(line)
            elif line.find("PM") != -1: 
                self.TList.append(line)
            elif line.find("+") != -1: 
                self.NList.append(line)
            elif line.find("sec") != -1: 
                self.DList.append(line)
            elif line.find("WAP") != -1: 
                self.YList.append(line)
                self.NList.insert(len(self.YList) - 1, "N/A")
            else:
                self.YList.append(line)
        f.close()    

    def populatePlan(self):
        index = 0 
        while index < len(self.TList):
            o = Conversation (self.TList[index], self.DList[index], self.NList[index], self.YList[index])
            self.plan.append(o)
            index += 1

    def prettyPrint(self, separator):
        for p in self.plan:
            p.prettyPrint(separator)


class Conversation:

    def __init__(self, time, duration, number, _type):
        self.time = time
        self.duration = duration
        self.number = number
        self._type = _type

    def prettyPrint(self, separator):
        f = open("output", "a")
        f.write(self.time + separator + self.duration + separator + self.number + separator + self._type + separator)
        f.close()


def main():
    p = PlanHandler('input')
    p.populatePlan()
    p.prettyPrint(" ")


if __name__ == '__main__':
    main()
<?php

$input = "
11PM
12PM
9AM
11AM
20sec
30sec
10sec
0sec
+70702211
+70703311
+70112111
PHONECALL
PHONECALL
WAP
SMS
";

function process($input) {

	$times = $durations = $numbers = $types = $output = array();
	
	$input_arr = explode("\r", trim($input));
	
	// print_r($input_arr);
	
	$section = 1;
	
	foreach ($input_arr as $key => $entry) {
		switch($section) {
			case 1:
				// time
				if (substr(trim($entry), -2) == 'AM' or substr(trim($entry), -2) == 'PM' ) {
					$times[] = $key;
					break;
				} else {
					$section ++;
				}
			
			case 2:
				// duration
				if (substr(trim($entry), -3) == 'sec') {
					$durations[] = $key;
					break;
				} else {
					$section ++;
				}		
			
			case 3:
				// number
				if (substr(trim($entry), 0, 1) == '+') {
					$numbers[] = $key;
					break;
				} else {
					$section ++;
				}		
			
			case 4:
				// type
				$types[] = $key;
			break;
		}
	}
	
	foreach ($types as $key => $type) {
		$row['time'] = trim($input_arr[array_shift($times)]);
		$row['duration'] = trim($input_arr[array_shift($durations)]);
		if (trim($input_arr[$type]) == "WAP") {
			$row['number'] = "N/A";		
		} else {
			$row['number'] = trim($input_arr[array_shift($numbers)]);	
		}
		$row['type'] = trim($input_arr[array_shift($types)]);
		$output[] = $row;
	}
	
	return $output;
}

?>

<pre>

<?php print_r(process($input)); ?>

</pre>
( needs comments... too lazy and proud to add them :-D )
ok here we ago with JAVA
class CallReport{
public static void main(String arg []){
System.out.println("11pm\t20sec\t+70702211\tphonecall\n12pm\t30sec\t+70703311\tphonecall\n9am\t30sec\tN/A\tWAP\n11AM\t0sec\t+70112111\tSMS);
}
}
nahh just kidding :/
i wanted to add something, i assumed the bad report will be readed from a text file and the results will wrote to a file as well
so here it is:
import java.io.*;
public class CallReport {

      public static String validateFile(String filepath, BufferedReader reader) throws IOException{
        String s = filepath;
        while(!(new File(s).exists()) && !(new File(s).isFile()))
        {
            System.out.println("File does not exist or file path wsn't inserted\n...enter a valid path: ");
            s = reader.readLine();
        }
        return s;
       }

    public static void main(String[] args)throws IOException {
	InputStreamReader isr = new InputStreamReader(System.in);
	BufferedReader reader = new BufferedReader(isr);
	System.out.print("Enter the report path: ");
	String path = validateFile(reader.readLine(),reader);
	reader = new BufferedReader(new FileReader(path));
        int counter = 0;int i,j;
        String info="";String t,d,n,y;
		t="";d="";n="";y="";
		while((t=reader.readLine())!=null)
		{
			info+=" "+t;
		}
		t="";	
        String data[]=info.split(" ");
        for(String s:data)
        {
            if(s.contains("AM")||s.contains("PM"))
                t=t+" "+s;
            else if(s.contains("sec"))
                d=d+" "+s;
            else if(s.startsWith("+"))
                n=n+" "+s;
            else
                y=y+" "+s;
        }
		t=t.substring(1);
		y=y.substring(2);
		n=n.substring(1);
		d=d.substring(1);
        String duration [] = d.split(" ");
        String time     [] = t.split(" ");
        String service  [] = y.split(" ");
        String nb       [] = n.split(" ");
        String numbers  [] = new String[service.length];
           i=0;j=0;
        for(String s:service)
        {
            if(!s.equals("WAP"))
            {
                numbers[i] = nb[j];
                i++;
                j++;
            }
            else
            {
                numbers[i] = "N/A\t";
                i++;
            }
        }
		BufferedWriter writer = new BufferedWriter(new FileWriter(path.substring(0,(path.lastIndexOf('.')))+"_NewReport.txt"));
		for(int x = 0;x<time.length ; x++)
		{
			System.out.println(time[x]+"\t\t"+duration[x]+"\t\t"+numbers[x]+"\t"+service[x]);
			writer.write(time[x]+"\t\t"+duration[x]+"\t\t"+numbers[x]+"\t"+service[x]);
			writer.newLine();
		}
				writer.close();
        		reader.close();
		
	}
}
2 years later
Very old thread, thought I'd add a simple solution in Python.
times,durations,numbers = [],[],[]
ti,du,nu = 0,0,0

for line in open('input.txt','r'):

    line = line.rstrip()
    
    if(line.endswith("AM") or line.endswith("PM")):
        times.append(line)

    elif(line.endswith("sec")):
        durations.append(line)

    elif(line[0] == "+" and len(line) == 9):
        numbers.append(line)

    elif(line in ("SMS","PHONECALL","WAP")):
        if(line == "WAP"):
            number = "n/a"
        else:
            number = numbers[nu]
            nu = nu + 1
            
        print "{0} {1} {2} {3}".format(times[ti],durations[du],number,line)
        ti = ti + 1
        du = du + 1

There is no need for more than one loop other than the one iterating over the lines of the file as long as the input data is organized the way shown above, and given that the list of types are at the end we use the same loop to iterate through them and compare their types and based on that increment the indexes of the other 3 lists holding the other info.
What the hell was I thinking when I first replied to MSD. Sometimes my past self embarrasses me. Anyway, it was 2 years ago.
@Ayman: Cool solution, how come you resurrected this thing?
@arithma haha, I was taking a look at exercises that I checked before all listed here
arithma wroteWhat the hell was I thinking when I first replied to MSD. Sometimes my past self embarrasses me. Anyway, it was 2 years ago.
@Ayman: Cool solution, how come you resurrected this thing?
It was like reading something khalil (if you remember) would post :)