Task: Rosetta Code_Rank languages by popularity




Go: package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var baseQuery = "http:
	"&format=xml&list=categorymembers&cmlimit=500"

func req(u string, foundCm func(string)) string {
	resp, err := http.Get(u)
	if err != nil {
		log.Fatal(err) 
	}
	defer resp.Body.Close()
	for p := xml.NewDecoder(resp.Body); ; {
		t, err := p.RawToken()
		switch s, ok := t.(xml.StartElement); {
		case err == io.EOF:
			return ""
		case err != nil:
			log.Fatal(err)
		case !ok:
			continue
		case s.Name.Local == "cm":
			for _, a := range s.Attr {
				if a.Name.Local == "title" {
					foundCm(a.Value)
				}
			}
		case s.Name.Local == "categorymembers" && len(s.Attr) > 0 &&
			s.Attr[0].Name.Local == "cmcontinue":
			return url.QueryEscape(s.Attr[0].Value)
		}
	}
	return ""
}


type pop struct {
	string
	int
}
type popList []pop

func (pl popList) Len() int      { return len(pl) }
func (pl popList) Swap(i, j int) { pl[i], pl[j] = pl[j], pl[i] }
func (pl popList) Less(i, j int) bool {
	switch d := pl[i].int - pl[j].int; {
	case d > 0:
		return true
	case d < 0:
		return false
	}
	return pl[i].string < pl[j].string
}

func main() {
	
	langMap := make(map[string]bool)
	storeLang := func(cm string) {
		if strings.HasPrefix(cm, "Category:") {
			cm = cm[9:]
		}
		langMap[cm] = true
	}
	languageQuery := baseQuery + "&cmtitle=Category:Programming_Languages"
	continueAt := req(languageQuery, storeLang)
	for continueAt != "" {
		continueAt = req(languageQuery+"&cmcontinue="+continueAt, storeLang)
	}
	
	s := make(popList, 0, len(langMap))

	
	resp, err := http.Get("http:
		"?title=Special:Categories&limit=5000")
	if err != nil {
		log.Fatal(err)
	}
	page, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	
	rx := regexp.MustCompile("<li><a.*>(.*)</a>.*[(]([0-9]+) member")
	for _, sm := range rx.FindAllSubmatch(page, -1) {
		ls := string(sm[1])
		if langMap[ls] {
			if n, err := strconv.Atoi(string(sm[2])); err == nil {
				s = append(s, pop{ls, n})
			}
		}
	}

	
	sort.Sort(s)
	lastCnt, lastIdx := -1, 1
	for i, lang := range s {
		if lang.int != lastCnt {
			lastCnt = lang.int
			lastIdx = i + 1
		}
		fmt.Printf("%3d. %3d - %s\n", lastIdx, lang.int, lang.string)
	}
}








Ada: with Ada.Integer_Text_IO;   use Ada.Integer_Text_IO;
with Ada.Strings.Fixed;     use Ada.Strings.Fixed;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO;           use Ada.Text_IO;

with Ada.Containers.Ordered_Sets;
with Ada.Strings.Less_Case_Insensitive;

with AWS.Client;
with AWS.Response;

procedure Test is

   use Ada.Strings;

   function "+" (S : String) return Unbounded_String renames To_Unbounded_String;

   type A_Language_Count is
      record
         Count    : Integer := 0;
         Language : Unbounded_String;
      end record;

   function "=" (L, R : A_Language_Count) return Boolean is
   begin
      return L.Language = R.Language;
   end "=";

   function "<" (L, R : A_Language_Count) return Boolean is
   begin
      
      return L.Count < R.Count
        or else (L.Count = R.Count
                 and then Less_Case_Insensitive (Left  => To_String (L.Language),
                                                 Right => To_String (R.Language)));
   end "<";

   package Sets is new Ada.Containers.Ordered_Sets (A_Language_Count);
   use Sets;

   Counts : Set;

   procedure Find_Counts (S : String) is
      Title_Str : constant String  := "title=""Category:";
      End_A_Str : constant String  := "</a> (";

      Title_At   : constant Natural := Index (S, Title_Str);
   begin
      if Title_At /= 0 then
         declare
            Bracket_At : constant Natural := Index (S (Title_At   + Title_Str'Length .. S'Last), ">");
            End_A_At   : constant Natural := Index (S (Bracket_At + 1                .. S'Last), End_A_Str);
            Space_At   : constant Natural := Index (S (End_A_At   + End_A_Str'Length .. S'Last), " ");
            Count      : constant Natural := Natural'Value (S (End_A_At + End_A_Str'Length .. Space_At - 1));
            Language   : constant String  :=                S (Title_At + Title_Str'Length .. Bracket_At - 2);
         begin
            if Bracket_At /= 0 and then End_A_At /= 0 and then Space_At /= 0 then
               begin
                  Counts.Insert (New_Item => (Count, +Language));
               exception
                  when Constraint_Error =>
                     Put_Line (Standard_Error, "Warning: repeated language: " & Language);
                     
                     null;
               end;
            end if;
            
            Find_Counts (S (Space_At + 1 .. S'Last));
         end;
      end if;

   end Find_Counts;

   Place : Natural := 1;

   procedure Display (C : Cursor) is
   begin
      Put (Place, Width => 1);             Put (". ");
      Put (Element (C).Count, Width => 1); Put (" - ");
      Put_Line (To_String (Element (C).Language));
      Place := Place + 1;
   end Display;
 
   Http_Source : constant AWS.Response.Data :=
     AWS.Client.Get ("http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000");
begin
   Find_Counts (AWS.Response.Message_Body (Http_Source));
   Counts.Reverse_Iterate (Display'Access);
end Test;