Hi all, I've written a backend which will take phone clues and generate placenames from the areacode. Areacode data (from free sources on the web) for the UK and US is provided. Problems: I'm not sure how to setup the path to the areacode data. How should I do this? What kind of clue should this generate? Address? Keyword? Textblock? Or should we consider a new keyword such as "place"? My own feeling is that a "place" keyword for places which aren't full addresses is a good idea. Longer term ideas: I'd like to integrate this with Edd's lat/long work (generate lat/long clues). Maybe do similar things with postcode / zip code data as well. More detailed data for the US might be useful, the area codes seem pretty big. I like the idea of dashboard doing useful things (e.g. maps) with geographic data, I think that has a lot of potential. Please let me know what you think. Cheers, dave
Attachment:
areacodes.tar.bz2
Description: application/bzip
// // GNOME Dashboard // // PhoneChainerBackend.cs: // // Author: // Dave Rodgman <davidr sucs org> // using System; using System.IO; using System.Collections; using System.Text; using System.Text.RegularExpressions; namespace Dashboard { class PhoneChainerBackend:Backend { public override bool Startup () { Name = "Phone Chainer"; // FIXME - this needs to be sorted out. Not sure of the best way to do it. String path = "areacodes"; StreamReader sr; SortedList table; DirectoryInfo dir = new DirectoryInfo (path); foreach (FileInfo file in dir.GetFiles ("areacodes.*.csv")) { String Country; try { sr = new StreamReader (new FileStream (file.FullName, FileMode.Open)); Country = sr.ReadLine ().Substring (1).Trim (null); if (!codeToAreaTable.ContainsKey (Country)) codeToAreaTable.Add (Country, new SortedList ()); table = (SortedList) codeToAreaTable [Country]; RegularExpressions.Match intlCodes = Regex.Match (sr.ReadLine (), @"#\+(\d+)\s*(\d*)"); table.Add ("CountryCode", intlCodes.Groups [1].Captures [0].ToString ()); table.Add ("CountryPrefix", intlCodes.Groups [2].Captures [0].ToString ()); } catch (Exception e) { Console.WriteLine ("PhoneChainer: Could not load area codes database: " + file.FullName); continue; } String line, code, area; Regex extractData = new Regex (@"\x22(?<code>\d+)\x22,\x22(?<town>[^\x22]+)\x22", RegexOptions.Compiled); while ((line = sr.ReadLine ()) != null) { if (line [0] == '#') continue; try { RegularExpressions.Match m = extractData.Match (line); area = m.Groups ["town"].Captures [0].ToString (); code = m.Groups ["code"].Captures [0].ToString (); if ((area.Length == 0) || (code.Length == 0)) throw new Exception (); } catch (Exception e) { Console.WriteLine ("PhoneChainer: error in {0} areacode data, line: {1}", Country, line); continue; } if (code.Length < minCodeLength) minCodeLength = code.Length; // We permit multiple towns per area code if (!table.ContainsKey (code)) table.Add (code, new ArrayList ()); ((ArrayList) (table [code])).Add (area); } Console.WriteLine ("PhoneChainer: Loaded {0} area codes", Country); } Console.WriteLine ("PhoneChainer backend started"); this.SubscribeToClues ("phone"); this.Initialized = true; return true; } private Hashtable codeToAreaTable = new Hashtable (); private int minCodeLength = 999999; private ArrayList lookupArea (String originalNumber) { ArrayList result = new ArrayList (); String number = Regex.Replace (originalNumber, @"[^\d\+]", ""); if (number.Length == 0) return result; IDictionaryEnumerator ie = codeToAreaTable.GetEnumerator (); while (ie.MoveNext ()) { SortedList table = (SortedList) (ie.Value); String code; // deal with international prefixes if (number [0] == '+') { code = number.Substring (1); if (!code.StartsWith ((String) (table ["CountryCode"]))) continue; code = table ["CountryPrefix"] + code.Substring (((String) (table ["CountryCode"])).Length); } else code = number; String key = null; for (int len = minCodeLength; len <= code.Length; len++) { int i = table.IndexOfKey (code.Substring (0, len)); if (i == -1) continue; key = code.Substring (0, len); } if (key == null) continue; foreach (String town in (ArrayList) table [key]) result.Add (town + ", " + ie.Key); } return result; } public override BackendResult ProcessCluePacket (CluePacket cp) { BackendResult result = new BackendResult (this, cp); foreach (Clue clue in cp.Clues) { if (!ClueTypeSubscribed (clue)) continue; ArrayList areas = lookupArea (clue.Text); foreach (String a in areas) { Clue areaClue = new Clue ("keyword", a, 10, clue); // FIXME is this the right cluetype? result.AddChainedClue (areaClue); } } return result; } } }