Rosetta Code/Rank languages by popularity

From Rosetta Code
Revision as of 13:52, 4 May 2021 by Blek (talk | contribs) (Ranking updated)


Task
Rosetta Code/Rank languages by popularity
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Sort the most popular computer programming languages based in number of members in Rosetta Code categories.

Sample output on 04 May 2021 at 15:50 +02:

Rank:  1 (1,355 entries) Phix
Rank:  2 (1,350 entries) Go
Rank:  3 (1,347 entries) Julia
Rank:  4 (1,325 entries) Raku
Rank:  5 (1,279 entries) Perl
Rank:  6 (1,237 entries) Python
Rank:  7 (1,124 entries) Kotlin
Rank:  8 (1,121 entries) C
Rank:  9 (1,116 entries) Wren
Rank: 10 (1,102 entries) Java
...


Notes
  •   Each language typically demonstrates one or two methods of accessing the data:
  •   The scraping and API solutions can be separate subsections, see the Tcl example.
  •   Filtering wrong results is optional.   You can check against Special:MostLinkedCategories (if using web scraping)
If you use the API, and do elect to filter, you may check your results against this complete, accurate, sortable, wikitable listing of all 944 programming languages, updated periodically, typically weekly.
  •   A complete ranked listing of all   798   languages (from the REXX example) is included here   ──►   output from the REXX program.



Ada

Library: AWS

<lang 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
     -- Sort by 'Count' and then by Language name
     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);
                    -- Ignore repeated results.
                    null;
              end;
           end if;
           -- Recursively parse the string for languages and counts
           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; </lang>

ALGOL 68

ALGOL68: using web scraping

Works with: ALGOL 68G version mk8+ for Unix and Linux - tested with release mk15-0.8b.fc9.i386 - uses non-standard library routines http content and grep in string.

Note: the routine http content is currently not available on Win32 systems.


This example is incorrect. Please fix the code and remove this message.

Details:
---among others, Tcl (the top dog) is missing.

<lang algol68>PROC good page = (REF STRING page) BOOL:

    IF grep in string("^HTTP/[0-9.]* 200", page, NIL, NIL) = 0
    THEN TRUE
    ELSE IF INT start, end;
             grep in string("^HTTP/[0-9.]* [0-9]+ [a-zA-Z ]*", page,
                            start, end) = 0
         THEN print (page[start : end])
         ELSE print ("unknown error retrieving page")
         FI;
         FALSE
    FI;

MODE LISTOFSTRING = STRUCT(REF LINK first, last, INT upb); MODE LINK = STRUCT(STRING value, REF LINK next);

PRIO LISTINIT = 1; OP LISTINIT = (REF LISTOFSTRING new, REF LINK first)REF LISTOFSTRING: (

 new := (first, first, (first IS REF LINK(NIL) | 0 | 1 ));
 new

);

OP +:= = (REF LISTOFSTRING list, []CHAR item)VOID: (

 HEAP LINK new := (STRING(item), REF LINK(NIL));
 IF first OF list IS REF LINK(NIL) THEN
   first OF list := new
 ELSE
   next OF last OF list := new
 FI;
 last OF list := new;
 upb OF list +:= 1

);

OP UPB = (LISTOFSTRING list)INT: upb OF list;

OP ARRAYOFSTRING = (LISTOFSTRING list)[]STRING:(

 [UPB list]STRING out;
 REF LINK this := first OF list;
 FOR i TO UPB list DO out[i] := value OF this; this := next OF this OD;
 out

);

INT match=0, no match=1, out of memory error=2, other error=3;

PROC re split = (STRING re split, REF STRING beetles)[]STRING:(

   LISTOFSTRING out := (NIL, NIL, 0); # LISTINIT REF LINK NIL; #
   INT start := 1, pos, end;
   WHILE grep in string(re split, beetles[start:], pos, end) = match DO
     out +:= beetles[start:start+pos-2];
     out +:= beetles[start+pos-1:start+end-1];
     start +:= end
   OD;
   IF start > UPB beetles THEN
     out +:= beetles[start:]
   FI;
   ARRAYOFSTRING(out)
 );


IF STRING reply;

  INT rc =
     http content (reply, "www.rosettacode.org", "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=500", 0);
  rc /= 0 OR NOT good page (reply)

THEN print (("Error:",strerror (rc))) ELSE

 STRING  # hack: HTML should be parsed by an official HTML parsing library #
   re html tag = "<[^>]*>",
   re a href category = "^<a href=""/wiki/Category:.*"" title=",
   re members = "([1-9][0-9]* members)";
 MODE STATISTIC = STRUCT(INT members, STRING category);
 FLEX[0]STATISTIC stats;
 OP +:=  = (REF FLEX[]STATISTIC in out, STATISTIC item)VOID:(
     [LWB in out: UPB in out+1]STATISTIC new;
     new[LWB in out: UPB in out]:=in out;
     new[UPB new]:=item;
     in out := new
   );
  1. hack: needs to be manually maintained #
 STRING re ignore ="Programming Tasks|WikiStubs|Maintenance/OmitCategoriesCreated|"+
                   "Unimplemented tasks by language|Programming Languages|"+
                   "Solutions by Programming Language|Implementations|"+
                   "Solutions by Library|Encyclopedia|Language users|"+
                   "Solutions by Programming Task|Basic language learning|"+
                   "RCTemplates|Language Implementations";
 FORMAT category fmt = $"<a href=""/wiki/Category:"g""" title=""Category:"g""""$;
 STRING encoded category, category;
 FORMAT members fmt = $" ("g" members)"$;
 INT members;
 FLEX[0]STRING tokens := re split(re html tag, reply);
 FOR token index TO UPB tokens DO
   STRING token := tokens[token index];
   FILE file;
   IF grep in string(re a href category, token, NIL, NIL) = match THEN
     associate(file, token);
     make term(file,"""");
     getf(file, (category fmt, encoded category, category));
     close(file)
   ELIF grep in string(re members, token, NIL, NIL) = match THEN
     IF grep in string(re ignore, category, NIL, NIL) /= match THEN
       associate(file, token);
       getf(file, (members fmt, members));
       stats +:= STATISTIC(members, category);
       close(file)
     FI
   FI
 OD;
 OP < = (STATISTIC a,b)BOOL:
   members OF a < members OF b;
 MODE SORTSTRUCT = STATISTIC;
 PR READ "prelude/sort.a68" PR;
 stats := in place shell sort reverse(stats);
 INT max = 10;
 FOR i TO (UPB stats > max | max | UPB stats) DO
   printf(($g(-0)". "g(-0)" - "gl$,i,stats[i]))
 OD

FI</lang>

Sample output:
1. 233 - Python
2. 222 - Ada
3. 203 - OCaml
4. 203 - C
5. 201 - Perl
6. 193 - Haskell
7. 182 - Java
8. 179 - D
9. 178 - ALGOL 68
10. 160 - Ruby

ALGOL 68:using the API

<lang algol68> CHAR line feed = REPR 10, carriage return = REPR 13; STRING crlf = carriage return + line feed; STRING domain = "rosettacode.org",

      page = "/mw/api.php?format=xml&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo";
  1. concatenate tuples #

OP + = ([]STRING a, b) []STRING:

  BEGIN
     [⌈a + ⌈b] STRING c;
     c[:⌈a] := a;
     c[⌈a+1:] := b;
     c
  END;
  1. count occurrances of string in string #

PROC count = (STRING sub, str) INT :

  BEGIN
     INT count := 0;
     IF UPB str ≥ UPB sub AND UPB str ≥ 1 THEN 

INT p := 1; INT p0; WHILE p + UPB sub - 1 <= UPB str ANDF (p0 := p; string in string (sub, p, str[p0:])) DO

           count +:= 1;

p +:= p0 + UPB sub - 1 OD

     FI;
     count
  END;
  1. split string into tuple #

PROC split = (STRING str, sep) FLEX[]STRING :

  BEGIN
     INT seplen = UPB sep, strlen = UPB str;
     INT cnt := 0, start := 1;
     INT p;
     [count (sep, str) + 1] STRING list;
     WHILE start ≤ strlen - (seplen - 1)

ANDF string in string (sep, p, str[start:]) DO p +:= start - 1; list[cnt +:= 1] := str[start:p-1]; start := p + seplen

     OD;
     IF cnt = 0 THEN list[cnt +:= 1] := str
     ELIF start ≤ strlen THEN list[cnt +:= 1] := str[start:]
     ELIF start = strlen + 1 AND seplen ≥ 1 THEN list[cnt +:= 1] := ""
     FI;
     list
  END;
  1. reverse strings in a TUPLE #

OP REVERSE = ([]STRING org) []STRING :

  BEGIN
     [UPB org]STRING new;
     FOR i TO UPB org DO

new[UPB org - (i - 1)] := org[i]

     OD;
     new
  END;
  1. convert unsigned number to INT #

OP TOINT = (STRING str) INT:

  BEGIN 
     INT p := 1, len := UPB str;
     WHILE p ≤ len ANDF is space (str[p]) DO p +:= 1 OD;
     IF str[1] = "-" OR str[1] = "+" THEN

p +:= 1

     FI;
     INT n := 0;
     WHILE p ≤ len ANDF is space (str[p]) DO p +:= 1 OD;
     FOR i FROM p TO len WHILE is digit (str[i]) DO 

n := n × 10 + ABS str[i] - ABS "0"

     OD;
     n
  END;
  1. pad to fixed width #

PROC field = (UNION (STRING,INT) x, INT w) STRING:

  BEGIN
     STRING s = (x | (INT i): whole (i,0), (STRING t): t);
     (w >= UPB s | " " * (w - UPB s)) + s
  END;

PROC get web page = (STRING host, path) STRING:

  BEGIN
     STRING reply;
     INT rc;
     # 'http content' sometimes fails with interrupted system call, so we loop until succeeding #
     WHILE  

# 'http content' makes requests that are not accepted by rosettacode.org, so therefore the hack # STRING hack = " HTTP/1.0" + crlf + "Host: rosettacode.org" + crlf +

                      "User-Agent: rank_languages_by_popularity";
        rc := http content (reply, host, path + hack, 0);

rc = 4

        DO SKIP 
     OD;
     IF rc = 0 AND grep in string ("^HTTP/[0-9.]+ 200", reply, NIL, NIL) = 0 THEN

INT p; IF string in string (crlf + crlf, p, reply) THEN STRING headers = reply[:p], body = reply[p+4:]; body ELSE "" FI

     ELSE 

print (strerror (rc)); ""

     FI
  END;
  1. the main program rank languages by popularity starts here #

STRING gcmcontinue; FLEX[0]STRING lines;

  1. get through API in chunks of 500 #

WHILE

  STRING body = get web page (domain, page + (gcmcontinue /= "" | "&gcmcontinue=" + gcmcontinue));
  INT b, e;
  gcmcontinue := (grep in string ("gcmcontinue=""([^""]+)", body, b, e) = 0 | body[b+13:e-1] | "");
  # split the XML into lines on </page> #
  lines := lines + split (body, "</page>");
  gcmcontinue /= "" DO SKIP 

OD;

  1. Each line is one language,
 go through them and rewrite them to something we can sort #

FOR i TO UPB lines DO

  STRING line = lines[i];
  STRING title;
  INT pages := 0;
  INT b, e;
  # the two fields we are intrested in are title="Category:xxx", and pages="999" #
  IF grep in string ("title=""Category:[^""]+""", line, b, e) = 0 THEN
     title := line[b+16:e-1]
  FI;
  IF grep in string ("pages=""[0-9]+""", line, b, e) = 0 THEN
     pages := TOINT line[b+7:e-1]
  FI;
  lines[i] := field (pages, 6) + " " + title

OD;

lines := REVERSE SORT lines;

INT rank := 1; BOOL tied := FALSE, lasttied := FALSE; print ((new line, whole (UPB lines, 0), " languages", new line, new line)); FOR i TO UPB lines DO

  INT entries = TOINT lines[i][:6];
  STRING lang = lines[i][8:];
  IF entries > 0 THEN 
     tied := i < UPB lines ANDF lines[i][:6] = lines[i+1][:6];
     print (("rank: ", field (rank,3), "  ", (tied OR lasttied | "[tied]" | " "*6),
             field ("(" + whole (entries,0) + " " + (entries = 1 | "entry)" | "entries)"), 20),
             "  ", lang, new line));
     IF NOT tied THEN rank +:= 1 FI;
     lasttied := tied
  FI 

OD</lang>

Sample output top 10:

572 languages

rank:   1               (883 entries)  Tcl
rank:   2               (875 entries)  Racket
rank:   3               (837 entries)  Python
rank:   4               (800 entries)  J
rank:   5               (772 entries)  Ruby
rank:   6               (763 entries)  Perl 6
rank:   7               (756 entries)  C
rank:   8               (742 entries)  Go
rank:   9               (737 entries)  D
rank:  10               (707 entries)  Perl

AutoHotkey

<lang autohotkey>MembsUrl = http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000 ValidUrl = http://rosettacode.org/wiki/Category:Programming_Languages WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")

Get the webpages

WebRequest.Open("GET", MembsUrl),WebRequest.Send() MembsPage := WebRequest.ResponseText WebRequest.Open("GET", ValidUrl),WebRequest.Send() ValidPage := WebRequest.ResponseText

Replace special characters

StringReplace, MembsPage, MembsPage, ΜC++, µC++, All StringReplace, MembsPage, MembsPage, МК-61/52, MK-61/52, All StringReplace, ValidPage, ValidPage, ΜC++, µC++, All StringReplace, ValidPage, ValidPage, МК-61/52, MK-61/52, All

ValidREx := "s)href=""([^""]+)"" title=""Category:([^""]+)"">(?=.*)"

MembsREx := "title=""Category:(.+?)"">.+?\((\d+) members?\)"

Iterate through all matches for valid languages

ValidLangs := [], FoundPos := 0 While FoundPos := RegExMatch(ValidPage, ValidREx, Match, FoundPos+1) ValidLangs[Match2] := Match1

Iterate through all matches for categories with members

MembsLangs := [], Dupes := [], Detected := 0, FoundPos := 0 While FoundPos := RegExMatch(MembsPage, MembsREx, Match, FoundPos+1) { ; If it isn't a valid language or is a duplicate, skip it if !ValidLangs.HasKey(Match1) || Dupes.HasKey(Match1) continue

Dupes.Insert(Match1, true) Detected++

; Initialize this member count if !IsObject(MembsLangs[Match2]) MembsLangs[Match2] := [Match1] else MembsLangs[Match2].Insert(Match1) }

Sort the languages with the highest member count first

Sorted := [] for Members, Languages in MembsLangs Sorted.Insert(1, [Members, Languages])

Initialize the GUI

Gui, New, HwndGuiHwnd Gui, Add, Text, w300 Center, %Detected% languages detected Gui, Add, Edit, w300 vSearchText gSearch, Filter languages Gui, Add, ListView, w300 r20 Grid gOpen vMyListView, Rank|Members|Category

Populate the list view

LV_ModifyCol(1, "Integer"), LV_ModifyCol(2, "Integer"), LV_ModifyCol(3, 186) for Rank, Languages in Sorted for Key, Language in Languages[2] LV_Add("", Rank, Languages[1], Language)

Gui, Show,, Rosetta Code return

Open: if (A_GuiEvent == "DoubleClick") { LV_GetText(Language, A_EventInfo, 3) Run, % "http://rosettacode.org" ValidLangs[Language] } return

Search: GuiControlGet, SearchText GuiControl, -Redraw, MyListView

LV_Delete() for Rank, Languages in Sorted for Key, Language in Languages[2] if InStr(Language, SearchText) LV_Add("", Rank, Languages[1], Language)

GuiControl, +Redraw, MyListView return

GuiClose: ExitApp return</lang>

AWK

Works with: Gawk

By using the API

This is the third solution. The first solution used web scraping with an external program ns for networking. The second solution used the Rosetta Code API instead of web scraping, but continued use of ns which for unknown reasons didn't work correctly. This solution uses native gawk networking to connect to the API at 500 items per request ("gmcontinue").

<lang awk>function join(array, start, end, sep, result, i) {

       result = array[start]
       for (i = start + 1; i <= end; i++)
           result = result sep array[i]
       return result

}

function trim(str) {

       gsub(/^blank:+|[[:blank:]\n]+$/, "", str)
       return str

}

function http2var( site,path,server,j,output) {

       RS = ORS = "\r\n"
       site = "rosettacode.org"
       path = "/mw/api.php" \
           "?action=query" \
           "&generator=categorymembers" \
           "&gcmtitle=Category:Programming%20Languages" \
           "&gcmlimit=500" \
           (gcmcontinue "" ? "&gcmcontinue=" gcmcontinue : "") \
           "&prop=categoryinfo" \
           "&format=txt"
       server = "/inet/tcp/0/" site "/80"
       print "GET " path " HTTP/1.0" |& server
       print "Host: " site |& server
       print "" |& server
       while ((server |& getline) > 0) {
           if($0 != 0) {
               j++
               output[j] = $0
           }
       }
       close(server)
       if(length(output) == 0)
           return -1
       else
           return join(output, 1, j, "\n")

}

function parse(webpage ,c,a,i,b,e,pages) {

      # Check for API continue code ie. a new page of results available
       match(webpage, "gcmcontinue[]] =>[^)]+[^)]", a)
       if(a[0] != "") {
           split(a[0], b, ">")
           gcmcontinue = trim(b[2])
       } else gcmcontinue = ""
       c = split(webpage, a, "[[][0-9]{1,7}[]]")
       while(i++ < c) {
           if(match(a[i], /[pages]/)) {
               match(a[i], "pages[]] =>[^[]+[^[]", b)
               split(b[0], e, ">")
               pages = trim(e[2]) + 0
           } else pages = 0
           if(match(a[i], /[title]/)) {
               match(a[i], "title[]] =>[^[]+[^[]", b)
               split(b[0], e, ":")
               e[2] = trim(e[2])
               if ( substr(e[2], length(e[2]), 1) == ")" )
                   e[2] = trim( substr(e[2], 1, length(e[2]) - 1) )
               if(length(e[2]) > 0)
                   G[e[2]] = pages
           }
       }

}

BEGIN {

       parse( http2var() )     # First 500
       while ( gcmcontinue != "" )
           parse( http2var() ) # Next 500, etc
       # https://www.gnu.org/software/gawk/manual/html_node/Controlling-Scanning.html
       PROCINFO["sorted_in"] = "@val_type_desc"
       for ( language in G )
           print ++i ". " language " - " G[language]

}</lang>

Output from 26 May 2015:
1. Tcl - 867
2. Racket - 863
3. Python - 828
4. J - 777
5. Ruby - 769
6. Perl 6 - 755
7. C - 751
...
570. NQP - 0
571. AspectC++ - 0
572. Cilk - 0
573. PL/M - 0
574. Agda2 - 0

BBC BASIC

Note that language names differing only in their case are merged. <lang bbcbasic> INSTALL @lib$+"SORTLIB"

     SortUp% = FN_sortinit(0,0)   : REM Ascending
     SortDown% = FN_sortinit(1,0) : REM Descending
     
     VDU 23,22,640;512;8,16,16,128+8 : REM Enable UTF-8 support
     DIM lang$(1000), tasks%(1000)
     NORM_IGNORECASE = 1
     
     SYS "LoadLibrary", "URLMON.DLL" TO urlmon%
     SYS "GetProcAddress", urlmon%, "URLDownloadToFileA" TO UDTF
     
     PRINT "Downloading languages list..."
     url$ = "http://rosettacode.org/wiki/Category:Programming_Languages"
     file$ = @tmp$ + "languages.htm"
     SYS UDTF, 0, url$, file$, 0, 0 TO fail%
     IF fail% ERROR 100, "File download failed (languages)"
     
     file% = OPENIN(file$)
     index% = 0
     WHILE NOT EOF#file%
       REPEAT
         a$ = GET$#file%
         IF INSTR(a$, "<a href=""/wiki/Category") = 0 EXIT REPEAT
         i% = INSTR(a$, "</a>")
         IF i% = 0 EXIT REPEAT
         j% = i%
         REPEAT i% -= 1 : UNTIL MID$(a$,i%,1) = ">" OR i% = 0
         IF i% = 0 EXIT REPEAT
         lang$(index%) = MID$(a$, i%+1, j%-i%-1)
         IF lang$(index%) <> "Languages" index% += 1
       UNTIL TRUE
     ENDWHILE
     CLOSE #file%
     
     C% = index%
     CALL SortUp%, lang$(0)
     
     PRINT "Downloading categories list..."
     url$ = "http://www.rosettacode.org/w/index.php"
     url$ += "?title=Special:Categories&limit=5000"
     file$ = @tmp$ + "categories.htm"
     SYS UDTF, 0, url$, file$, 0, 0 TO fail%
     IF fail% ERROR 100, "File download failed (categories)"
     
     file% = OPENIN(file$)
     WHILE NOT EOF#file%
       REPEAT
         a$ = GET$#file%
         i% = INSTR(a$, "member")
         IF i% = 0 EXIT REPEAT
         REPEAT i% -= 1 : UNTIL MID$(a$,i%,1) = "(" OR i% = 0
         IF i% = 0 EXIT REPEAT
         tasks% = VAL(MID$(a$, i%+1))
         IF tasks% = 0 EXIT REPEAT
         REPEAT i% -= 1 : UNTIL MID$(a$,i%,1) = "<" OR i% = 0
         IF i% = 0 EXIT REPEAT
         j% = i%
         REPEAT i% -= 1 : UNTIL MID$(a$,i%,1) = ">" OR i% = 0
         IF i% = 0 EXIT REPEAT
         k% = FNwhere(lang$(), MID$(a$, i%+1, j%-i%-1), index%-1)
         IF k% <> -1 tasks%(k%) += tasks%
       UNTIL TRUE
     ENDWHILE
     CLOSE #file%
     
     CALL SortDown%, tasks%(0), lang$(0)
     
     VDU 14
     @% = 3 : REM Column width
     PRINT "List of languages as of " TIME$
     FOR i% = 0 TO index%-1
       IF tasks%(i%) = 0 EXIT FOR
       PRINT  i%+1 ". " tasks%(i%) " - " lang$(i%)
     NEXT
     END
     
     DEF FNwhere(a$(), S$, T%)
     LOCAL B%, C%, H%
     H% = 2
     WHILE H%<T% H% *= 2:ENDWHILE
     H% /= 2
     REPEAT
       IF (B%+H%)<=T% THEN
         SYS "CompareString", 0, NORM_IGNORECASE, S$, -1, a$(B%+H%), -1 TO C%
         IF C% >= 2 B% += H%
       ENDIF
       H% /= 2
     UNTIL H%=0
     SYS "CompareString", 0, NORM_IGNORECASE, S$, -1, a$(B%), -1 TO C%
     IF C% = 2 THEN = B% ELSE = -1</lang>

Output:

Downloading languages list...
Downloading categories list...
List of languages as of Sat.17 Nov 2012,00:21:11
  1. 682 - Tcl
  2. 638 - Python
  3. 626 - PicoLisp
  4. 622 - C
  5. 592 - J
  6. 581 - Go
  7. 570 - Ruby
  8. 553 - Ada
  9. 515 - Perl
 10. 514 - D
 11. 507 - Haskell
 12. 490 - Perl 6
 13. 489 - BBC BASIC
 14. 477 - Java
 15. 473 - Mathematica
 16. 469 - PureBasic
 17. 469 - OCaml
 18. 459 - Unicon
 19. 438 - REXX
 20. 428 - Icon
......
461.   1 - ScriptBasic
462.   1 - Qore
463.   1 - Opa
464.   1 - Nickle
465.   1 - Neko
466.   1 - Neat
467.   1 - MEL
468.   1 - MAPPER
469.   1 - Kotlin
470.   1 - Chapel

Bracmat

<lang bracmat> ( get-page

 =   url type
   .   !arg:(?url.?type)
     & sys$(str$("wget -q -O wget.out \"" !url \"))
     & get$("wget.out",!type)                     { Type can be JSN, X ML, HT ML or just ML. }
 )

& ( get-langs

 =   arr lang
   .   :?arr
     & !arg:? (.h2.) ?arg (h2.?) ?      { Only analyse part of page between the h2 elements. }
     &   whl
       ' ( !arg
         :   ?
             ( a
             .   ?
                 ( title
                 .   @(?:"Category:" ?):?lang
                   & !lang !arr:?arr
                 )
                 ?
             )
             ?arg
         )
     & !arr
 )

& ( get-cats

 =   page langs list count pat li A Z
   .   !arg:(?page.?langs)
     & 0:?list
     &   whl
       ' ( !langs:%?lang ?langs
         &                                { Use macro substitution to create a fast pattern. }
             ' ( ?
                 (a.? (title.$lang) ?)           { $lang is replaced by the actual language. }
                 ?
                 (.a.)
                 @(?:? #?count " " ?)
               )
           : (=?pat)
         &       (       !page
                       :   ?A
                           ( (li.) ?li (.li.) ?Z
                           & !li:!pat
                           )
                     & !A !Z:?page     { Remove found item from page. (Not necessary at all.)}
                     & !count
                   | 0                                       { The language has no examples. }
                 . 
                 )
               \L !lang             { Bracmat normalizes a\Lx+b\Ly+a\Lz to a\L(x*z)+b\Ly, so }
             + !list                { it's easy to collect categories with the same count.   }
           : ?list
         )
     & !list
 )

& get-cats

   $ (   get-page
       $ ( "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000"
         . HT,ML
         )
     .   get-langs
       $ ( get-page
         $ ( "http://rosettacode.org/wiki/Category:Programming_Languages"
           . HT ML
           )
         )
     )
 : ?cats

& :?list & whl

 ' ( !cats:(?count.)\L?tiedcats+?cats
   & :?ties
   &   whl
     ' ( !tiedcats:@(?:"Category:" ?name)*?tiedcats
       & !ties !name:?ties
       )
   & (!count.!ties) !list:?list
   )

& 1:?rank & whl

 ' ( !rank:?tiedRank
   & !list:(?count.?ties) ?list
   &   whl
     ' ( !ties:%?name ?ties
       & @(!tiedRank:? [?len)                  { We want some padding for the highest ranks. }
       & @("   ":? [!len ?sp)                  { Skip blanks up to the length of the rank.   }
       & out$(str$(!sp !tiedRank ". " !count " - " !name))
       & 1+!rank:?rank
       )
   )

& ;</lang> Output:

  1. 816 - Tcl
  2. 771 - Racket
  3. 760 - Python
  4. 708 - C
  5. 705 - Perl 6
  6. 700 - J
  7. 695 - Ruby
  8. 690 - D
  9. 656 - Go
 10. 643 - PicoLisp
 11. 639 - Perl
 12. 622 - REXX
 13. 602 - Ada
 14. 591 - Mathematica
 15. 588 - Haskell
 16. 574 - AutoHotkey
 17. 559 - Unicon
 18. 543 - Java
 19. 526 - BBC BASIC
 20. 510 - Icon
 21. 500 - C++
...
498. 1 - Vox
498. 1 - XPath 2.0
498. 1 - Xanadu
523. 0 - Clarion
523. 0 - EhBASIC
523. 0 - Epigram
523. 0 - FLORA-2
523. 0 - Florid
523. 0 - Jcon
523. 0 - LLP
523. 0 - Lolli
523. 0 - Lygon
523. 0 - Monte
523. 0 - ObjectIcon
523. 0 - RPGIV
523. 0 - Rubylog
523. 0 - Star
523. 0 - True BASIC
523. 0 - X10
523. 0 - XS
523. 0 - Ya

C

This example is incorrect. Please fix the code and remove this message.

Details: Compiles without error but "Segmentation fault" when run. Tested on Cygwin, SuSE Linux and Arch Linux (Manjaro)


This example is in need of improvement:

This solution uses an external program wget for networking, but it could use Library: libcurl (see Web scraping#C) for example. Also this solution scrapes Special:Categories &limit 5000 which will break if the HTML style changes or the number of languages exceeds 5000. It could use the MediWiki API to get the language names and pages in a single call, in blocks of 500 until complete with no upper limit. See the Awk example. If you make an API-based version please retain the web-scrapping version in its own sub-section (following the lead of TCL on this page).

Ghetto parser<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>

const char * lang_url = "http://www.rosettacode.org/w/api.php?action=query&" "list=categorymembers&cmtitle=Category:Programming_Languages&" "cmlimit=500&format=json"; const char * cat_url = "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000";

  1. define BLOCK 1024

char *get_page(const char *url) { char cmd[1024]; char *ptr, *buf; int bytes_read = 1, len = 0; sprintf(cmd, "wget -q \"%s\" -O -", url); FILE *fp = popen(cmd, "r"); if (!fp) return 0; for (ptr = buf = 0; bytes_read > 0; ) { buf = realloc(buf, 1 + (len += BLOCK)); if (!ptr) ptr = buf; bytes_read = fread(ptr, 1, BLOCK, fp); if (bytes_read <= 0) break; ptr += bytes_read; } *++ptr = '\0'; return buf; }

char ** get_langs(char *buf, int *l) { char **arr = 0; for (*l = 0; (buf = strstr(buf, "Category:")) && (buf += 9); ++*l) for ( (*l)[arr = realloc(arr, sizeof(char*)*(1 + *l))] = buf; *buf != '"' || (*buf++ = 0); buf++);

return arr; }

typedef struct { const char *name; int count; } cnt_t; cnt_t * get_cats(char *buf, char ** langs, int len, int *ret_len) { char str[1024], *found; cnt_t *list = 0; int i, llen = 0; for (i = 0; i < len; i++) { sprintf(str, "/wiki/Category:%s", langs[i]); if (!(found = strstr(buf, str))) continue; buf = found + strlen(str);

if (!(found = strstr(buf, "</a> ("))) continue; list = realloc(list, sizeof(cnt_t) * ++llen); list[llen - 1].name = langs[i]; list[llen - 1].count = strtol(found + 6, 0, 10); } *ret_len = llen; return list; }

int _scmp(const void *a, const void *b) { int x = ((const cnt_t*)a)->count, y = ((const cnt_t*)b)->count; return x < y ? -1 : x > y; }

int main() { int len, clen; char ** langs = get_langs(get_page(lang_url), &len); cnt_t *cats = get_cats(get_page(cat_url), langs, len, &clen); qsort(cats, clen, sizeof(cnt_t), _scmp); while (--clen >= 0) printf("%4d %s\n", cats[clen].count, cats[clen].name);

return 0; }</lang>

Output:
 563 Tcl
 529 PicoLisp
 522 Python
 504 C
 500 J
 442 Go
 440 Ruby
 435 Ada
 430 PureBasic
 427 Perl
...


Library: libcurl

Using cJSON.
Compiled with gcc -lcurl -lm cJSON.c lang_rank.c
Usage: rank [number]
Outputs the first [number] languages in the list, default to 10. Use -1 to display all the languages. <lang c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>
  4. include <curl/curl.h>
  5. include "cJSON.h"

char *URL_BASE = "http://www.rosettacode.org/mw/api.php?format=json&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo&rawcontinue"; char *URL_BASE_CONT = "http://www.rosettacode.org/mw/api.php?format=json&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo&gcmcontinue=";

typedef struct mem { char *text; size_t size; } mem;

typedef struct page { char *name; int num; } page;

size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata); void curl_request(CURL *curl, char *url, mem *response); char *build_url(char *cont); char *get_cont(cJSON *json); void sort_arrays(page *pages, int *s); cJSON *parse_json(cJSON *json); page *fill_arrays(page *pages, int *s, cJSON *json);

int main(int argc, char *argv[]) { curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); char *cont = NULL; page *pages = malloc(1); int till = 10; int *npag = malloc(sizeof(int)); *npag = 0; if (argc>1) till = atoi(argv[1]); do { mem *response = calloc(1, sizeof(mem)); char *url = build_url(cont); if (cont) free(cont); curl_request(curl, url, response); cJSON *json = cJSON_Parse(response->text); cont = get_cont(json); cJSON *json_pages = parse_json(json); pages = fill_arrays(pages, npag, json_pages); cJSON_Delete(json); free(url); free(response->text); free(response); } while (cont); sort_arrays(pages, npag); if (till>*npag||till<-1) till=10; if (till==-1) till=*npag; for (int i = 0;i<till;i++) { printf("#%d: %s, %d tasks\n", i+1, pages[i].name, pages[i].num); } for (int i = 0;i<*npag;i++) { free(pages[i].name); } free(pages); free(npag); curl_easy_cleanup(curl); curl_global_cleanup(); return 0; } size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata) { mem *response = userdata; response->text = realloc(response->text, response->size+size*nmemb+1); memcpy(&(response->text[response->size]), ptr, size*nmemb); response->size += size*nmemb; response->text[response->size] = '\0'; return size*nmemb; } void curl_request(CURL *curl, char *url, mem *response) { curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, response); curl_easy_perform(curl); } char *build_url(char *cont) { char *url; if (cont) { int size = strlen(URL_BASE_CONT)+strlen(cont)+1; url = calloc(1, size); strncpy(url, URL_BASE_CONT, strlen(URL_BASE_CONT)); strcat(url, cont); } else { url = malloc(strlen(URL_BASE)+1); strcpy(url, URL_BASE); } return url; } cJSON *parse_json(cJSON *json) { cJSON *pages; if (json) { pages = cJSON_GetObjectItem(json, "query"); pages = cJSON_GetObjectItem(pages, "pages"); pages = pages->child; } return pages; } char *get_cont(cJSON *json) { cJSON *jcont = cJSON_GetObjectItem(json, "query-continue"); if (jcont && jcont->child->child) { char *cont = malloc(strlen(jcont->child->child->valuestring)+1); strcpy(cont, jcont->child->child->valuestring); return cont; } else { return NULL; } } page *fill_arrays(page *pag, int *i, cJSON *json) { cJSON *cur_page = json; page *pages = pag; do { pages = realloc(pages, *i*sizeof(page)+sizeof(page)); if (json->child) { int size = strlen(cur_page->child->next->next->valuestring)-9; char *lang = malloc(size+1); strcpy(lang, cur_page->child->next->next->valuestring+9); pages[*i].name = lang; } else { pages[*i].name = "no name"; } int task = cur_page->child->next->next->next?cur_page->child->next->next->next->child->valueint:0; pages[*i].num = task; *i = *i+1; cur_page = cur_page->next; } while (cur_page->next); return pages; } void sort_arrays(page *pages, int *size) { int sorted = 0; do { sorted = 1; for (int i = 0;i<*size-1;i++) { if (pages[i].num<pages[i+1].num) { sorted = 0; int a = pages[i+1].num; pages[i+1].num = pages[i].num; pages[i].num = a; char *s = pages[i+1].name; pages[i+1].name = pages[i].name; pages[i].name = s; } } } while (sorted!=1); } </lang>

Output:
1. Racket: 907 tasks
2. Tcl: 899 tasks
3. Python: 872 tasks
4. J: 848 tasks
5. Perl 6: 813 tasks
6. Ruby: 796 tasks
7. C: 777 tasks
8. Java: 764 tasks
9. Go: 759 tasks
10. D: 749 tasks

C#

Sorting only programming languages. <lang csharp>using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text.RegularExpressions;

class Program {

   static void Main(string[] args)
   {
       string get1 = new WebClient().DownloadString("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=500&format=json");
       string get2 = new WebClient().DownloadString("http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000");
       ArrayList langs = new ArrayList();
       Dictionary<string, int> qtdmbr = new Dictionary<string, int>();
       MatchCollection match1 = new Regex("\"title\":\"Category:(.+?)\"").Matches(get1);
       MatchCollection match2 = new Regex("title=\"Category:(.+?)\">.+?</a>[^(]*\\((\\d+) members\\)").Matches(get2);
       foreach (Match lang in match1) langs.Add(lang.Groups[1].Value);
       foreach (Match match in match2)
       {
           if (langs.Contains(match.Groups[1].Value))
           {
               qtdmbr.Add(match.Groups[1].Value, Int32.Parse(match.Groups[2].Value));
           }
       }
       string[] test = qtdmbr.OrderByDescending(x => x.Value).Select(x => String.Format("{0,3} - {1}", x.Value, x.Key)).ToArray();
       int count = 1;
       foreach (string i in test)
       {
           Console.WriteLine("{0,3}. {1}", count, i);
           count++;
       }
   }

}</lang>

Output (as of May 30, 2010):
 1. 397 - Tcl
 2. 368 - Python
 3. 350 - Ruby
 4. 333 - J
 5. 332 - C
 6. 322 - Haskell
 7. 322 - OCaml
 8. 302 - Perl
 9. 290 - Common Lisp
10. 289 - AutoHotkey
    . . .

Object-oriented solution

<lang csharp>using System; using System.Net; using System.Linq; using System.Text.RegularExpressions; using System.Collections.Generic;

class Category {

   private string _title;
   private int _members;
   public Category(string title, int members) {
       _title = title;
       _members = members;
   }
   public string Title {
       get {
           return _title;
       }
   }
   public int Members {
       get {
           return _members;
       }
   }

}

class Program {

   static void Main(string[] args) {
       string get1 = new WebClient().DownloadString("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=500&format=json");
       string get2 = new WebClient().DownloadString("http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000");
       MatchCollection match1 = new Regex("\"title\":\"Category:(.+?)\"").Matches(get1);
       MatchCollection match2 = new Regex("title=\"Category:(.+?)\">.+?</a>[^(]*\\((\\d+) members\\)").Matches(get2);
       string[] valids = match1.Cast<Match>().Select(x => x.Groups[1].Value).ToArray();
       List<Category> langs = new List<Category>();
       foreach (Match match in match2) {
           string category = match.Groups[1].Value;
           int members = Int32.Parse(match.Groups[2].Value);
           if (valids.Contains(category)) langs.Add(new Category(category, members));
       }
       langs = langs.OrderByDescending(x => x.Members).ToList();
       int count = 1;
       foreach (Category i in langs) {
           Console.WriteLine("{0,3}. {1,3} - {2}", count, i.Members, i.Title);
           count++;
       }
   }

}</lang>

C++

Library: Boost

using g++ under Linux with g++ -lboost_thread -lboost_system -lboost_regex: <lang cpp>#include <string>

  1. include <boost/regex.hpp>
  2. include <boost/asio.hpp>
  3. include <vector>
  4. include <utility>
  5. include <iostream>
  6. include <sstream>
  7. include <cstdlib>
  8. include <algorithm>
  9. include <iomanip>

struct Sort { //sorting programming languages according to frequency

  bool operator( ) ( const std::pair<std::string,int> & a , const std::pair<std::string,int> & b ) 
     const {

return a.second > b.second ;

     }

} ;

int main( ) {

  try {
     //setting up an io service , with templated subelements for resolver and query
     boost::asio::io_service io_service ; 
     boost::asio::ip::tcp::resolver resolver ( io_service ) ;
     boost::asio::ip::tcp::resolver::query query ( "rosettacode.org" , "http" ) ;
     boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve( query ) ;
     boost::asio::ip::tcp::resolver::iterator end ;
     boost::asio::ip::tcp::socket socket( io_service ) ;
     boost::system::error_code error = boost::asio::error::host_not_found ;
     //looking for an endpoint the socket will be able to connect to
     while ( error && endpoint_iterator != end ) {

socket.close( ) ; socket.connect( *endpoint_iterator++ , error ) ;

     }
     if ( error ) 

throw boost::system::system_error ( error ) ;

     //we send a request
     boost::asio::streambuf request ;
     std::ostream request_stream( &request ) ;
     request_stream << "GET " << "/mw/index.php?title=Special:Categories&limit=5000" << " HTTP/1.0\r\n" ;
     request_stream << "Host: " << "rosettacode.org" << "\r\n" ;
     request_stream << "Accept: */*\r\n" ;
     request_stream << "Connection: close\r\n\r\n" ;
     //send the request
     boost::asio::write( socket , request ) ;
     //we receive the response analyzing every line and storing the programming language 
     boost::asio::streambuf response ;
     std::istream response_stream ( &response ) ;
     boost::asio::read_until( socket , response , "\r\n\r\n" ) ;

boost::regex e( "

  • <a href=\"[^<>]+?\">([a-zA-Z\\+#1-9]+?)</a>\\s?\\((\\d+) members\\)
  • " ) ; //using the wrong regex produces incorrect sorting!! std::ostringstream line ; std::vector<std::pair<std::string , int> > languages ; //holds language and number of examples boost::smatch matches ; while ( boost::asio::read( socket , response , boost::asio::transfer_at_least( 1 ) , error ) ) { line << &response ; if ( boost::regex_search( line.str( ) , matches , e ) ) { std::string lang( matches[2].first , matches[2].second ) ; int zahl = atoi ( lang.c_str( ) ) ; languages.push_back( std::make_pair( matches[ 1 ] , zahl ) ) ; } line.str( "") ;//we have to erase the string buffer for the next read } if ( error != boost::asio::error::eof ) throw boost::system::system_error( error ) ; //we sort the vector entries , see the struct above std::sort( languages.begin( ) , languages.end( ) , Sort( ) ) ; int n = 1 ; for ( std::vector<std::pair<std::string , int> >::const_iterator spi = languages.begin( ) ; spi != languages.end( ) ; ++spi ) { std::cout << std::setw( 3 ) << std::right << n << '.' << std::setw( 4 ) << std::right << spi->second << " - " << spi->first << '\n' ; n++ ; } } catch ( std::exception &ex ) { std::cout << "Exception: " << ex.what( ) << '\n' ; } return 0 ; }</lang>

    Sample output (just the "top ten"):
     1. 367 - Tcl
     2. 334 - Python
     3. 319 - Ruby
     4. 286 - C
     5. 277 - Perl
     6. 272 - OCaml
     7. 264 - Ada
     8. 241 - E
     9. 239 - AutoHotkey
    10. 193 - Forth
    

    Caché ObjectScript

    <lang cos>Class Utils.Net.RosettaCode [ Abstract ] {

    ClassMethod GetTopLanguages(pHost As %String = "", pPath As %String = "", pTop As %Integer = 10) As %Status { // check input parameters If $Match(pHost, "^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$")=0 { Quit $$$ERROR($$$GeneralError, "Invalid host name.") }

    // create http request and get page Set req=##class(%Net.HttpRequest).%New() Set req.Server=pHost Do req.Get(pPath)

    // create xml stream with doc type Set xml=##class(%Stream.GlobalCharacter).%New() Set sc=xml.WriteLine("<!DOCTYPE doc_type [") Set sc=xml.WriteLine($Char(9)_"<!ENTITY nbsp ' '>") Set sc=xml.WriteLine($Char(9)_"<!ENTITY amp '&'>") Set sc=xml.WriteLine("]>")

    // copy xhtml stream to xml stream Set xhtml=req.HttpResponse.Data Set xhtml.LineTerminator=$Char(10) While 'xhtml.AtEnd { Set line=xhtml.ReadLine() If line["!DOCTYPE" Continue If line["<g:plusone></g:plusone>" { Continue Set line="<g:plusone xmlns:g='http://base.google.com/ns/1.0'></g:plusone>" } Set sc=xml.WriteLine(line) }

    // create an instance of an %XML.XPATH.Document Set sc=##class(%XML.XPATH.Document).CreateFromStream(xml, .xdoc) If $$$ISERR(sc) Quit sc

    // evaluate following 'XPath' expression Set sc=xdoc.EvaluateExpression("//div[@id='bodyContent']//li", "a[contains(@href, '/Category:')]/ancestor::li", .res)

    // iterate through list elements Set array=##class(%ArrayOfDataTypes).%New() Do { Set dom=res.GetNext(.key) If '$IsObject(dom) Quit

    // get language name and members Set lang="" While dom.Read() { If 'dom.HasValue Continue If lang="" { If $Locate(dom.Value, "User|Tasks|Omit|attention|operations|Solutions by") Quit Set lang=dom.Value Continue } If dom.Value["members" { Set members=+$ZStrip(dom.Value, "<>P") Set list=array.GetAt(members) Set $List(list, $ListLength(list)+1)=lang Set sc=array.SetAt(list, members) Quit } } } While key'="" If array.Count()=0 Quit $$$ERROR($$$GeneralError, "No languages found.")

    // show top entries Write "Top "_pTop_" Languages (as at "_$ZDate($HoroLog, 2)_"):", ! For count=1:1:pTop { Set members=array.GetPrevious(.key) If key="" Quit Write $Justify(count, 3), ". ", key, " - ", $ListToString(members, ", "), ! }

    // finished Quit $$$OK }

    }</lang>

    Example:
    USER>Do ##class(Utils.Net.RosettaCode).GetTopLanguages("www.rosettacode.org", "/mw/index.php?title=Special:Categories&limit=5000")
    Top 10 Languages (as at 21 Apr 2013):
      1. 728 - Tcl
      2. 668 - Python
      3. 654 - C
      4. 630 - J
      5. 626 - PicoLisp
      6. 595 - D
      7. 590 - Ruby
      8. 589 - Go
      9. 576 - Perl 6
     10. 567 - Ada
    

    D

    With dmd you need compile like "dmd rosetta_popularity.d -L-lphobos2 -L-lcurl". <lang d>void main() {

       import std.stdio, std.algorithm, std.conv, std.array, std.regex,
              std.typecons, std.net.curl;
    
       immutable r1 = `"title":"Category:([^"]+)"`;
       const languages = get("www.rosettacode.org/w/api.php?action=query"~
                             "&list=categorymembers&cmtitle=Category:Pro"~
                             "gramming_Languages&cmlimit=500&format=json")
                         .matchAll(r1).map!q{ a[1].dup }.array;
    
       auto pairs = get("www.rosettacode.org/w/index.php?" ~
                         "title=Special:Categories&limit=5000")
                     .matchAll(`title="Category:([^"]+)">[^<]+` ~
                               `</a>[^(]+\((\d+) members\)`)
                     .filter!(m => languages.canFind(m[1]))
                     .map!(m => tuple(m[2].to!uint, m[1].dup));
    
       foreach (i, res; pairs.array.sort!q{a > b}.release)
           writefln("%3d. %3d - %s", i + 1, res[]);
    

    }</lang>

    Sample output (top twenty as of 2013-01-24):
      1. 717 - Tcl
      2. 663 - Python
      3. 643 - C
      4. 626 - PicoLisp
      5. 622 - J
      6. 587 - Go
      7. 587 - Ruby
      8. 585 - D
      9. 568 - Perl 6
     10. 564 - Ada
     11. 554 - Mathematica
     12. 535 - Perl
     13. 532 - Haskell
     14. 514 - BBC BASIC
     15. 505 - REXX
     16. 491 - Java
     17. 478 - OCaml
     18. 469 - PureBasic
     19. 462 - Unicon
     20. 430 - AutoHotkey

    Delphi

    Library: IdHttp
    Library: IdComponent
    Library: IdIOHandler
    Library: IdSSL

    For safe run, download dlls: libeay32.dll & ssleay32.dll, then put in executable path. <lang Delphi> program Rank_languages_by_popularity;

    {$APPTYPE CONSOLE}

    {$R *.res}

    uses

     System.SysUtils,
     System.Classes,
     IdHttp,
     IdBaseComponent,
     IdComponent,
     IdIOHandler,
     IdIOHandlerSocket,
     IdIOHandlerStack,
     IdSSL,
     IdSSLOpenSSL,
     System.RegularExpressions,
     System.Generics.Collections,
     System.Generics.Defaults;
    

    const

     AURL = 'https://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000';
     UserAgent =
       'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36';
    

    type

     TPair = record
       Language: string;
       Users: Integer;
       constructor Create(lang, user: string);
     end;
    
     TPairs = TList<TPair>;
    


     { TPair }
    

    constructor TPair.Create(lang, user: string); begin

     Language := lang;
     Users := StrToIntDef(user, 0);
    

    end;

    function GetFullCode: string; begin

     with TIdHttp.create(nil) do
     begin
       HandleRedirects := True;
       Request.UserAgent := UserAgent;
       IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
       Result := Get(AURL);
       IOHandler.Free;
       Free;
     end;
    

    end;

    function GetList(const Code: string): TPairs; var

     RegularExpression: TRegEx;
     Match: TMatch;
     language, users: string;
    

    begin

     Result := TPairs.Create;
    
     RegularExpression.Create('>(?<LANG>[^<,;]*)<\/a>.. \((?<USERS>[,\d]*)');
     Match := RegularExpression.Match(Code);
    
     while Match.Success do
     begin
       users := Match.Groups.Item['USERS'].Value.Replace(',', );
       language := Match.Groups.Item['LANG'].Value;
    
       Result.Add(TPair.Create(language, users));
       Match := Match.NextMatch;
     end;
    

    end;

    procedure Sort(List: TPairs); begin

     List.Sort(TComparer<TPair>.Construct(
       function(const Left, Right: TPair): Integer
       begin
         result := Right.Users - Left.Users;
         if result = 0 then
           result := CompareText(Left.Language, Right.Language);
       end));
    

    end;

    function SumUsers(List: TPairs): Cardinal; var

     p: TPair;
    

    begin

     Result := 0;
     for p in List do
     begin
       Inc(Result, p.Users);
     end;
    

    end;

    var

     Data: TStringList;
     Code, line: string;
     List: TPairs;
     i: Integer;
    

    begin

     Data := TStringList.Create;
     Writeln('Downloading code...');
    
     Code := GetFullCode;
     data.Clear;
    
     List := GetList(Code);
    
     Sort(List);
    
     Writeln('Total languages: ', List.Count);
     Writeln('Total Users: ', SumUsers(List));
     Writeln('Top 10:'#10);
    
     for i := 0 to List.Count - 1 do
     begin
       line := Format('%5dth %5d %s', [i + 1, List[i].users, List[i].language]);
       Data.Add(line);
       if i < 10 then
         Writeln(line);
     end;
    
     Data.SaveToFile('Rank.txt');
     List.Free;
     Data.Free;
    
     Readln;
    

    end.

    </lang>

    Output (as of Jul 27, 2020):
    Downloading code...
    Total languages: 3267
    Total Users: 96532
    Top 10:
    
        1th  1261 Go
        2th  1228 Phix
        3th  1221 Julia
        4th  1210 Raku
        5th  1148 Python
        6th  1139 Perl
        7th  1090 Kotlin
        8th  1053 C
        9th  1052 Java
       10th  1051 Racket
    

    Erlang

    <lang Erlang> -module( rank_languages_by_popularity ).

    -export( [task/0] ).

    -record( print_fold, {place=0, place_step=1, previous_count=0} ).

    task() -> ok = find_unimplemented_tasks:init(), Category_programming_languages = find_unimplemented_tasks:rosetta_code_list_of( "Programming_Languages" ), Programming_languages = [X || "Category:" ++ X <- Category_programming_languages], {ok, {{_HTTP,200,"OK"}, _Headers, Body}} = httpc:request( "http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000" ), Count_categories = lists:sort( [{Y, X} || {X, Y} <- category_counts(Body, []), lists:member(X, Programming_languages)] ), lists:foldr( fun place_count_category_write/2, #print_fold{}, Count_categories ).


    category_counts( "", [[] | Acc] ) -> Acc; category_counts( String, Acc ) -> {Begin, End} = category_count_begin_end( String ), {Category_count, String_continuation} = category_count_extract( String, Begin, End ), category_counts( String_continuation, [Category_count | Acc] ).

    category_count_begin_end( String ) -> Begin = string:str( String, "/wiki/Category:" ), End = string:str( string:substr(String, Begin), " member" ), category_count_begin_end( Begin, End, erlang:length(" member") ).

    category_count_begin_end( _Begin, 0, _End_length ) -> {0, 0}; category_count_begin_end( Begin, End, End_length ) -> {Begin, Begin + End + End_length}.

    category_count_extract( _String, 0, _End ) -> {[], ""}; category_count_extract( String, Begin, End ) -> Category_count = category_count_extract( string:substr(String, Begin, End - Begin) ), {Category_count, string:substr( String, End + 1 )}.

    category_count_extract( "/wiki/Category:" ++ T ) -> Category_member = string:tokens( T, " " ), Category = category_count_extract_category( Category_member ), Member = category_count_extract_count( lists:reverse(Category_member) ), {Category, Member}.

    category_count_extract_category( [Category | _T] ) -> lists:map( fun category_count_extract_category_map/1, string:strip(Category, right, $") ).

    category_count_extract_category_map( $_ ) -> $\s; category_count_extract_category_map( Character ) -> Character.

    category_count_extract_count( ["member" ++ _, "(" ++ N | _T] ) -> erlang:list_to_integer( N ); category_count_extract_count( _T ) -> 0.

    place_count_category_write( {Count, Category}, Acc ) -> Print_fold = place_count_category_write( Count, Acc ), io:fwrite("~p. ~p - ~p~n", [Print_fold#print_fold.place, Count, Category] ), Print_fold;

    place_count_category_write( Count, #print_fold{place_step=Place_step, previous_count=Count}=Print_fold ) -> Print_fold#print_fold{place_step=Place_step + 1}; place_count_category_write( Count, #print_fold{place=Place, place_step=Place_step} ) -> #print_fold{place=Place + Place_step, previous_count=Count}. </lang>

    Sample output (top/last ten as of 2013-05-27):
    1. 741 - "Tcl"
    2. 676 - "Python"
    3. 660 - "C"
    4. 638 - "J"
    5. 627 - "PicoLisp"
    6. 609 - "Perl 6"
    6. 609 - "D"
    8. 607 - "Racket"
    9. 592 - "Ruby"
    10. 589 - "Go"
    ...
    454. 1 - "Opa"
    454. 1 - "Nickle"
    454. 1 - "NewtonScript"
    454. 1 - "Neko"
    454. 1 - "Neat"
    454. 1 - "MEL"
    454. 1 - "MAPPER"
    454. 1 - "LiveScript"
    454. 1 - "Kotlin"
    454. 1 - "Jacquard Loom"
    

    F#

    <lang fsharp>open System open System.Text.RegularExpressions

    [<EntryPoint>] let main argv =

       let rosettacodeSpecialCategoriesAddress =
           "http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000"
       let rosettacodeProgrammingLaguagesAddress =
           "http://rosettacode.org/wiki/Category:Programming_Languages"
    
       let getWebContent (url :string)  =
           using (new System.Net.WebClient()) (fun x -> x.DownloadString url)
    
       let regexForTitleCategoryFollowedOptionallyByMembercount =
           new Regex("""
               title="Category: (?<Name> [^"]* ) ">    # capture the name of the category
               (                   # group begin for optional part
                   [^(]*           # ignore up to next open paren (on this line)
                   \(              # verbatim open paren
                       (?<Number>
                           \d+     # a number (= some digits)
                       )
                       \s+         # whitespace
                       member(s?)  # verbatim text members (maybe singular)
                   \)              # verbatim closing paren
               )?                  # end of optional part
               """, // " <- Make syntax highlighting happy
               RegexOptions.IgnorePatternWhitespace ||| RegexOptions.ExplicitCapture)
       let matchesForTitleCategoryFollowedOptionallyByMembercount str =
           regexForTitleCategoryFollowedOptionallyByMembercount.Matches(str)
    
       let languages =
           matchesForTitleCategoryFollowedOptionallyByMembercount
               (getWebContent rosettacodeProgrammingLaguagesAddress)
           |> Seq.cast
           |> Seq.map (fun (m: Match) -> (m.Groups.Item("Name").Value, true))
           |> Map.ofSeq
    
       let entriesWithCount =
           let parse str = match Int32.TryParse(str) with | (true, n) -> n | (false, _) -> -1
           matchesForTitleCategoryFollowedOptionallyByMembercount
               (getWebContent rosettacodeSpecialCategoriesAddress)
           |> Seq.cast
           |> Seq.map (fun (m: Match) ->
               (m.Groups.Item("Name").Value, parse (m.Groups.Item("Number").Value)))
           |> Seq.filter (fun p -> (snd p) > 0 &&  Map.containsKey (fst p) languages)
           |> Seq.sortBy (fun x -> -(snd x))
           
    
       Seq.iter2 (fun i x -> printfn "%4d. %s" i x)
           (seq { 1 .. 20 })
           (entriesWithCount |> Seq.map (fun x -> sprintf "%3d - %s" (snd x) (fst x)))
       0</lang>
    

    Showing top 20 as of 2013-04-02

       1. 721 - Tcl
       2. 665 - Python
       3. 647 - C
       4. 626 - PicoLisp
       5. 622 - J
       6. 588 - Go
       7. 588 - Ruby
       8. 585 - D
       9. 569 - Perl 6
      10. 565 - Ada
      11. 555 - Mathematica
      12. 535 - Perl
      13. 533 - Haskell
      14. 514 - BBC BASIC
      15. 505 - REXX
      16. 491 - Java
      17. 480 - OCaml
      18. 469 - PureBasic
      19. 462 - Unicon
      20. 430 - AutoHotkey

    Go

    <lang go>package main

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

    var baseQuery = "http://rosettacode.org/mw/api.php?action=query" + "&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) // connection or request fail } 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 "" }

    // satisfy sort interface (reverse sorting) 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() { // get languages, store in a map 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) } // allocate slice for sorting s := make(popList, 0, len(langMap))

    // get big list of categories resp, err := http.Get("http://rosettacode.org/mw/index.php" + "?title=Special:Categories&limit=5000") if err != nil { log.Fatal(err) } page, err := ioutil.ReadAll(resp.Body) resp.Body.Close()

    // split out fields of interest and populate sortable slice

    rx := regexp.MustCompile("

  • <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}) } } } // output 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) } }</lang>
    Output on 11 Aug 2014:
      1. 832 - Tcl
      2. 783 - Racket
      3. 774 - Python
      4. 733 - Perl 6
      5. 729 - J
    …
    506.   1 - Supernova
    506.   1 - TestML
    506.   1 - Vox
    506.   1 - XPath 2.0
    506.   1 - Xanadu
    

    (All the final entries are tied for spot 506, there are 530 lines.)

    Groovy

    <lang groovy>def html = new URL('http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000').getText([

           connectTimeout:500,
           readTimeout:15000,
           requestProperties: [ 'User-Agent': 'Firefox/2.0.0.4']])
    

    def count = [:]

    (html =~ '
  • <a[^>]+>([^<]+)</a>[^(]*[(](\\d+) member[s]*[)]
  • ').each { match, language, members -> count[language] = (members as int) } count.sort { v1, v2 -> v2.value <=> v1.value }.eachWithIndex { value, index -> println "${index + 1} $value" }</lang> Output:

    1 Tcl=766
    2 Racket=726
    3 Python=712
    4 Programming Tasks=695
    5 C=681
    6 Perl 6=649
    ...
    48 Groovy=323

    Haskell

    Haskell: Using the API

    <lang haskell>{-# LANGUAGE OverloadedStrings #-}

    import Data.Aeson import Network.HTTP.Base (urlEncode) import Network.HTTP.Conduit (simpleHttp) import Data.List (sortBy, groupBy) import Data.Function (on) import Data.Map (Map, toList)

    -- Record representing a single language. data Language =

       Language { 
           name      :: String,
           quantity  :: Int
       } deriving (Show)
    

    -- Make Language an instance of FromJSON for parsing of query response. instance FromJSON Language where

       parseJSON (Object p) = do
           categoryInfo <- p .:? "categoryinfo" 
    
           let quantity = case categoryInfo of
                              Just ob -> ob .: "size"
                              Nothing -> return 0
    
               name = p .: "title"
    
           Language <$> name <*> quantity
    

    -- Record representing entire response to query. -- Contains collection of languages and optional continuation string. data Report =

       Report { 
           continue    :: Maybe String,
           languages   :: Map String Language
       } deriving (Show)
    

    -- Make Report an instance of FromJSON for parsing of query response. instance FromJSON Report where

       parseJSON (Object p) = do
           querycontinue <- p .:? "query-continue"
    
           let continue 
                   = case querycontinue of
                         Just ob -> fmap Just $ 
                                        (ob .: "categorymembers") >>= 
                                        (   .: "gcmcontinue")
                         Nothing -> return Nothing
    
               languages = (p .: "query") >>= (.: "pages") 
    
           Report <$> continue <*> languages
    

    -- Pretty print a single language showLanguage :: Int -> Bool -> Language -> IO () showLanguage rank tie (Language languageName languageQuantity) =

       let rankStr = show rank
       in putStrLn $ rankStr ++ "." ++ 
                         replicate (4 - length rankStr) ' ' ++
                         (if tie then " (tie)" else "      ") ++
                         " " ++ drop 9 languageName ++
                         " - " ++ show languageQuantity
    

    -- Pretty print languages with common rank showRanking :: (Int, [Language]) -> IO () showRanking (ranking, languages) =

       mapM_ (showLanguage ranking $ length languages > 1) languages
    

    -- Sort and group languages by rank, then pretty print them. showLanguages :: [Language] -> IO () showLanguages allLanguages =

       mapM_ showRanking $ 
             zip [1..] $ 
             groupBy ((==) `on` quantity) $
             sortBy (flip compare `on` quantity) allLanguages
    

    -- Mediawiki api style query to send to rosettacode.org queryStr = "http://rosettacode.org/mw/api.php?" ++

              "format=json" ++ 
              "&action=query" ++ 
              "&generator=categorymembers" ++ 
              "&gcmtitle=Category:Programming%20Languages" ++ 
              "&gcmlimit=100" ++ 
              "&prop=categoryinfo" 
    

    -- Issue query to get a list of Language descriptions runQuery :: [Language] -> String -> IO () runQuery ls query = do

       Just (Report continue langs) <- decode <$> simpleHttp query 
       let accLanguages = ls ++ map snd (toList langs)
    
       case continue of
           -- If there is no continue string we are done so display the accumulated languages.
           Nothing -> showLanguages accLanguages
    
           -- If there is a continue string, recursively continue the query.
           Just continueStr -> do
               let continueQueryStr = queryStr ++ "&gcmcontinue=" ++ urlEncode continueStr
               runQuery accLanguages continueQueryStr
    

    main :: IO () main = runQuery [] queryStr</lang>

    Output:

    (As of 2015-07-29.) Here we show only the top 30.

    1.          Tcl - 887
    2.          Racket - 877
    3.          Python - 853
    4.          J - 795
    5.          Ruby - 775
    6.          Perl 6 - 766
    7.          C - 757
    8.          Go - 746
    9.          D - 740
    10.         Perl - 710
    11.         REXX - 697
    12.         PicoLisp - 692
    13.         Haskell - 682
    14.         Mathematica - 675
    15.         Java - 652
    16.         Zkl - 634
    17.         Ada - 623
    18.         AutoHotkey - 591
    19.         Unicon - 581
    20.         C++ - 562
    21.         Common Lisp - 551
    22.         Scala - 548
    23.         BBC BASIC - 532
    24.         Icon - 523
    25.         C sharp - 516
    26.         OCaml - 508
    27.         Nim - 502
    28.   (tie) Clojure - 485
    28.   (tie) PureBasic - 485
    29.         Erlang - 455
    30.         PARI/GP - 441

    Haskell: Using web scraping

    Scraping the languages and categories pages. <lang haskell>import Network.Browser import Network.HTTP import Network.URI import Data.List import Data.Maybe import Text.XML.Light import Control.Arrow import Data.Ord

    getRespons url = do

       rsp <- Network.Browser.browse $ do
         setAllowRedirects True
         setOutHandler $ const (return ())     -- quiet
         request $ getRequest url
       return $ rspBody $ snd rsp
    


    mostPopLang = do

     rsp <-getRespons $ "http://www.rosettacode.org/w/api.php?action=query&list=" ++ 
    

    "categorymembers&cmtitle=Category:Programming_Languages&cmlimit=500&format=xml"

     mbrs <- getRespons "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000" 
     let xmls = onlyElems $ parseXML rsp
         langs = concatMap (map ((\\"Category:"). fromJust.findAttr (unqual "title")). filterElementsName (== unqual "cm")) xmls
    
     let catMbr = second (read.takeWhile(/=' '). drop 6). break (=='<'). drop 1. dropWhile(/='>') . drop 5
         catNmbs :: [(String, Int)]
    

    catNmbs = map catMbr $ filter (isPrefixOf "

  • ") $ lines mbrs printFmt (n,(l,m)) = putStrLn $ take 6 (show n ++ ". ") ++ (show m) ++ " " ++ l toMaybe (a,b) = case b of Just x -> Just (a,x) _ -> Nothing mapM_ printFmt $ zip [1..] $ sortBy (flip (comparing snd)) $ mapMaybe (toMaybe. (id &&& flip lookup catNmbs)) langs</lang>
    First 20:
    *Main> mostPopLang
    1.    421  Tcl
    2.    392  Python
    3.    365  PicoLisp
    4.    363  J
    5.    360  Ruby
    6.    354  C
    7.    344  Haskell
    8.    337  OCaml
    9.    316  Perl
    10.   308  PureBasic
    11.   302  AutoHotkey
    12.   299  Common Lisp
    13.   295  D
    14.   295  Java
    15.   293  Ada
    16.   278  Oz
    17.   260  R
    18.   259  C sharp
    19.   257  C++
    20.   255  ALGOL 68

    HicEst

    <lang hicest>CHARACTER cats*50000, catlist*50000, sortedCat*50000, sample*100 DIMENSION RankNr(1)

     READ(ClipBoard) cats
     catlist = ' '
     pos = 1 ! find language entries like    * 100 doors (2 members)
     nr = 0
     ! after next '*' find next "name" = '100 doors' and next "(...)" = '(2 members)' :
    

    1 EDIT(Text=cats, SetPos=pos, Right='*', R, Mark1, R='(', Left, M2, Parse=name, R=2, P=members, GetPos=pos)

     IF(pos > 0) THEN
         READ(Text=members) count
         IF(count > 0) T