Rosetta Code/Rank languages by popularity: Difference between revisions
No edit summary |
JoseAlexis (talk | contribs) |
||
Line 1: | Line 1: | ||
[[Category:Networking and Web Interaction]] |
|||
[[Category:Sorting]] |
|||
Sort most popular programming languages based in number of members in Rosetta Code categories (from http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=500) |
|||
[[Category:Rosetta Code related]] |
|||
{{task|Text processing}} |
|||
;Task: |
|||
Sort the most popular computer programming languages based in number of members in Rosetta Code categories. |
|||
Sample output on 02 August 2022 at 09:50 +02 |
|||
<pre>Rank: 1 (1,565 entries) Phix |
|||
Rank: 2 (1,558 entries) Wren |
|||
Rank: 3 (1,531 entries) Julia |
|||
Rank: 4 (1,507 entries) Raku |
|||
Rank: 5 (1,500 entries) Go |
|||
Rank: 6 (1,466 entries) Perl |
|||
Rank: 7 (1,409 entries) Python |
|||
Rank: 8 (1,402 entries) Nim |
|||
Rank: 9 (1,254 entries) J |
|||
Rank: 10 (1,211 entries) C |
|||
...</pre> |
|||
;Notes: |
|||
* Each language typically demonstrates one or two methods of accessing the data: |
|||
:::* with web scraping (via http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000) |
|||
:::* with the API method (examples below for [[Rosetta Code/Rank languages by popularity#AWK|Awk]], [[Rosetta Code/Rank languages by popularity#Perl|Perl]], [[Rosetta Code/Rank languages by popularity#Ruby|Ruby]], [[Rosetta Code/Rank languages by popularity#Tcl|Tcl]], etc). |
|||
* The scraping and API solutions can be separate subsections, see the [[Rosetta Code/Rank languages by popularity#Tcl|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 [[Rosetta_Code/Rank_languages_by_popularity/Full_list|this complete, accurate, sortable, wikitable listing]] of all '''{{PAGESINCAT:Programming Languages}}''' [[:Category:Programming Languages|programming languages]], updated periodically, ''typically weekly''. |
|||
* A complete ranked listing of all '''813''' languages (from the REXX example) is included here ──► [[RC_POP.OUT|output from the REXX program]]. |
|||
<br><br> |
|||
=={{header|Ada}}== |
|||
===Ada 2022: using web scraping=== |
|||
{{libheader|AWS}} |
|||
<syntaxhighlight lang="ada">pragma Ada_2022; |
|||
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.Unbounded.Less_Case_Insensitive; |
|||
with Ada.Characters.Handling; use Ada.Characters.Handling; |
|||
with AWS.Client; use AWS.Client; |
|||
with AWS.Messages; use AWS.Messages; |
|||
with AWS.Response; |
|||
procedure Rank_Languages_By_Popularity is |
|||
use Ada.Strings; |
|||
function "+" (S : String) return Unbounded_String |
|||
renames To_Unbounded_String; |
|||
type A_Language_Count is |
|||
record |
|||
Count : Natural := 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 => L.Language, |
|||
Right => R.Language)); |
|||
end "<"; |
|||
package Sets is new Ada.Containers.Ordered_Sets (A_Language_Count); |
|||
use Sets; |
|||
Counts : Set; |
|||
procedure Find_Counts (S : String) is |
|||
function Strip_Character (S : String; C : Character) return String is |
|||
S_Copy_Str : String (1 .. S'Length); |
|||
S_Copy_Index : Natural := 0; |
|||
begin |
|||
for I in S'Range loop |
|||
if S (I) /= C then |
|||
S_Copy_Index := S_Copy_Index + 1; |
|||
S_Copy_Str (S_Copy_Index) := S (I); |
|||
end if; |
|||
end loop; |
|||
return S_Copy_Str (S_Copy_Str'First .. S_Copy_Index); |
|||
end Strip_Character; |
|||
function Ignore_Category (L : String) return Boolean is |
|||
type Unbounded_String_Array is array (Positive range <>) |
|||
of Unbounded_String; |
|||
-- This list is quite comprehensive, but not complete |
|||
Categories_To_Ignore : Unbounded_String_Array := [ |
|||
+"Pages with syntax highlighting errors", |
|||
+"Programming", |
|||
+"Examples needing attention", |
|||
+"Tasks needing attention", |
|||
+"Language users", |
|||
+"Implementations", |
|||
+"Solutions by ", |
|||
+"Maintenance/OmitCategoriesCreated", |
|||
+"Collection Members", |
|||
+"Pages with too many expensive parser function calls", |
|||
+"Garbage collection", |
|||
+" User", |
|||
+"SQL User", |
|||
+"Typing", |
|||
+"Parameter passing", |
|||
+"Execution method", |
|||
+"Unimplemented tasks by language", |
|||
+"Wolfram Language", |
|||
+"/Omit", |
|||
+"Wren-", |
|||
+"WrenGo", |
|||
+"Phix/", |
|||
+"PhixClass", |
|||
+"Basic language learning", |
|||
+"Encyclopedia", |
|||
+"RCTemplates", |
|||
+"SysUtils", |
|||
+"Action! ", |
|||
+"Text processing", |
|||
+"Image processing", |
|||
+"Scala Digital Signal Processing", |
|||
+"List processing", |
|||
+"Digital signal processing", |
|||
+"Processing Python", |
|||
+"Classic CS problems and programs", |
|||
+"Brainf*** related", |
|||
+"Data Structures", |
|||
+"Perl modules", |
|||
+"Perl/", |
|||
+"Perl:LWP", |
|||
+"Perl 6 related", |
|||
+"Flow control", |
|||
+"Excessively difficult task", |
|||
+"WikiStubs", |
|||
+"Impl needed", |
|||
+"Recursion" |
|||
]; |
|||
begin |
|||
for Category of Categories_To_Ignore loop |
|||
declare |
|||
Category_At : constant Natural := |
|||
Index (+To_Lower (L), |
|||
To_Lower (To_String (Category))); |
|||
begin |
|||
if Category_At /= 0 then |
|||
return True; |
|||
end if; |
|||
end; |
|||
end loop; |
|||
return False; |
|||
end Ignore_Category; |
|||
Title_Str : constant String := "title=""Category:"; |
|||
End_A_Tag_Str : constant String := "</a>"; |
|||
Space_Paren_Str : constant String := " ("; |
|||
Title_At : constant Natural := Index (S, Title_Str); |
|||
begin |
|||
if Title_At /= 0 then |
|||
declare |
|||
Closing_Bracket_At : constant Natural := |
|||
Index (S (Title_At + Title_Str'Length .. S'Last), ">"); |
|||
End_A_Tag_At : constant Natural := |
|||
Index (S (Closing_Bracket_At + 1 .. S'Last), End_A_Tag_Str); |
|||
Language : constant String := |
|||
S (Closing_Bracket_At + 1 .. End_A_Tag_At - 1); |
|||
Space_Paren_At : constant Natural := |
|||
Index (S (End_A_Tag_At + 1 .. S'Last), Space_Paren_Str); |
|||
Space_At : constant Natural := |
|||
Index (S (Space_Paren_At + Space_Paren_Str'Length + 1 |
|||
.. S'Last), |
|||
" "); |
|||
Count : constant Natural := |
|||
Natural'Value ( |
|||
Strip_Character ( |
|||
S (Space_Paren_At + |
|||
Space_Paren_Str'Length |
|||
.. Space_At - 1), |
|||
',')); |
|||
begin |
|||
if Closing_Bracket_At /= 0 |
|||
and then End_A_Tag_At /= 0 |
|||
and then Space_Paren_At /= 0 |
|||
and then Space_At /= 0 |
|||
then |
|||
begin |
|||
if Ignore_Category (Language) = False then |
|||
Counts.Insert (New_Item => (Count, +Language)); |
|||
end if; |
|||
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/w/index.php?" & |
|||
"title=Special:Categories&limit=5000", |
|||
Follow_Redirection => True); |
|||
Status : Status_Code; |
|||
begin |
|||
Put_Line ("Getting website data..."); |
|||
Status := AWS.Response.Status_Code (Http_Source); |
|||
if Status not in Success then |
|||
Put_Line ("Unable to retrieve data => Status Code :" & |
|||
Image (Status) & |
|||
" Reason :" & Reason_Phrase (Status)); |
|||
raise Connection_Error; |
|||
end if; |
|||
Put_Line ("Finding categories..."); |
|||
Find_Counts (AWS.Response.Message_Body (Http_Source)); |
|||
Put_Line ("Displaying categories..."); |
|||
Counts.Reverse_Iterate (Display'Access); |
|||
Put_Line ("Process complete."); |
|||
end Rank_Languages_By_Popularity; |
|||
</syntaxhighlight> |
|||
{{out|Sample output}} |
|||
<pre> |
|||
1. 1683 - Phix |
|||
2. 1676 - Wren |
|||
3. 1653 - Julia |
|||
4. 1623 - Raku |
|||
5. 1577 - Nim |
|||
6. 1553 - Go |
|||
7. 1548 - Perl |
|||
8. 1532 - Python |
|||
9. 1416 - J |
|||
10. 1349 - Java |
|||
11. 1333 - FreeBASIC |
|||
12. 1300 - C |
|||
13. 1282 - C++ |
|||
14. 1239 - Ruby |
|||
15. 1209 - Mathematica |
|||
16. 1175 - Haskell |
|||
17. 1156 - REXX |
|||
18. 1152 - Kotlin |
|||
19. 1149 - Jq |
|||
20. 1102 - Racket |
|||
21. 1055 - Sidef |
|||
22. 1021 - ALGOL 68 |
|||
23. 1017 - 11l |
|||
24. 1012 - Zkl |
|||
25. 1004 - Factor |
|||
26. 993 - D |
|||
27. 989 - C sharp |
|||
28. 987 - Tcl |
|||
29. 973 - Scala |
|||
30. 959 - Ada |
|||
31. 954 - Rust |
|||
32. 949 - Delphi |
|||
33. 947 - Lua |
|||
34. 868 - F Sharp |
|||
35. 867 - XPL0 |
|||
</pre> |
|||
=={{header|ALGOL 68}}== |
|||
===ALGOL68: using web scraping=== |
|||
<!-- {{does not work with|ALGOL 68|Standard - extensions to language used}} --> |
|||
{{works with|ALGOL 68G|mk8+ for Unix and Linux - tested with release mk15-0.8b.fc9.i386 - uses non-standard library routines ''http content'' and'' grep in string''.}} |
|||
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386 - ''http content'' and'' grep in string'' not available in any library ... yet}} --> |
|||
<!-- # the ''good page'' routine was extracted from ALGOL 68G's manual (GPL code) # --> |
|||
Note: the routine ''http content'' is currently not available on Win32 systems. |
|||
{{incorrect|ALGOL 68| <br> ---among others, Tcl (the top dog) is missing. <br>}} |
|||
<syntaxhighlight 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 |
|||
); |
|||
# 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</syntaxhighlight> |
|||
{{out|Sample output}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
===ALGOL 68:using the API=== |
|||
<syntaxhighlight 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"; |
|||
# concatenate tuples # |
|||
OP + = ([]STRING a, b) []STRING: |
|||
BEGIN |
|||
[⌈a + ⌈b] STRING c; |
|||
c[:⌈a] := a; |
|||
c[⌈a+1:] := b; |
|||
c |
|||
END; |
|||
# 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; |
|||
# 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; |
|||
# 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; |
|||
# 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; |
|||
# 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; |
|||
# the main program rank languages by popularity starts here # |
|||
STRING gcmcontinue; |
|||
FLEX[0]STRING lines; |
|||
# 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; |
|||
# 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</syntaxhighlight> |
|||
{{out|Sample output top 10}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|AutoHotkey}}== |
|||
<syntaxhighlight 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:([^""]+)"">(?=.*</table>)" |
|||
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</syntaxhighlight> |
|||
=={{header|AWK}}== |
|||
{{works with|Gawk}} |
|||
===By using the API=== |
|||
This is the third solution. The [http://rosettacode.org/mw/index.php?title=Rosetta_Code/Rank_languages_by_popularity&oldid=102962#AWK first solution] used web scraping with an external program '''ns''' for networking. The [http://rosettacode.org/mw/index.php?title=Rosetta_Code/Rank_languages_by_popularity&oldid=204081 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"). |
|||
<syntaxhighlight 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] |
|||
}</syntaxhighlight> |
|||
{{out|Output from 26 May 2015}} |
|||
<pre>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 |
|||
</pre> |
|||
=={{header|BBC BASIC}}== |
|||
{{works with|BBC BASIC for Windows}} |
|||
Note that language names differing only in their case are merged. |
|||
<syntaxhighlight 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</syntaxhighlight> |
|||
'''Output:''' |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|Bracmat}}== |
|||
<syntaxhighlight 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 |
|||
) |
|||
) |
|||
& ;</syntaxhighlight> |
|||
Output: |
Output: |
||
<pre> 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</pre> |
|||
=={{header|C}}== |
|||
{{incorrect|C|Compiles without error but "Segmentation fault" when run. Tested on Cygwin, SuSE Linux and Arch Linux (Manjaro)}} |
|||
{{improve|C|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 [[Rosetta_Code/Rank_languages_by_popularity#Tcl|TCL on this page]]). }} |
|||
Ghetto parser<syntaxhighlight lang="c">#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#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"; |
|||
#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; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 563 Tcl |
|||
529 PicoLisp |
|||
522 Python |
|||
504 C |
|||
500 J |
|||
442 Go |
|||
440 Ruby |
|||
435 Ada |
|||
430 PureBasic |
|||
427 Perl |
|||
...</pre> |
|||
{{libheader|libcurl}} |
|||
Using cJSON.<br> |
|||
Compiled with gcc -lcurl -lm cJSON.c lang_rank.c <br> |
|||
Usage: rank [number]<br> |
|||
Outputs the first [number] languages in the list, default to 10. Use -1 to display all the languages. |
|||
<syntaxhighlight lang="c"> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <curl/curl.h> |
|||
#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); |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
<pre> |
||
1. Racket: 907 tasks |
|||
1. 246 - Programming_Tasks |
|||
2. |
2. Tcl: 899 tasks |
||
3. |
3. Python: 872 tasks |
||
4. |
4. J: 848 tasks |
||
5. |
5. Perl 6: 813 tasks |
||
6. |
6. Ruby: 796 tasks |
||
7. |
7. C: 777 tasks |
||
8. |
8. Java: 764 tasks |
||
9. |
9. Go: 759 tasks |
||
10. |
10. D: 749 tasks |
||
</pre> |
|||
=={{header|C sharp|C#}}== |
|||
Sorting only programming languages.<br> |
|||
Note that this does not distinguish between tasks and non-task categories, so the counts can exceed the total number of tasks.<br> |
|||
Note this may need to set the Security Protocol type to Tls12 - see the section Problem running the C# entry in [[Talk:Rosetta_Code/Count_examples]] |
|||
<syntaxhighlight 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 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>(); |
|||
string cmcontinue = ""; |
|||
do |
|||
{ |
|||
string get1 = new WebClient().DownloadString("http://www.rosettacode.org/w/api.php?" |
|||
+"action=query&list=categorymembers" |
|||
+"&cmtitle=Category:Programming_Languages" |
|||
+"&cmlimit=500&format=json" |
|||
+cmcontinue |
|||
); |
|||
cmcontinue = ""; |
|||
MatchCollection languageMatch = new Regex("\"title\":\"Category:(.+?)\"").Matches(get1); |
|||
MatchCollection cmcontinueMatch = new Regex("cmcontinue\":\"([a-z0-9A-Z|]*)\"").Matches(get1); |
|||
foreach (Match lang in languageMatch) langs.Add(lang.Groups[1].Value); |
|||
foreach (Match more in cmcontinueMatch) cmcontinue = "&cmcontinue=" + more.Groups[1].Value; |
|||
} |
|||
while( cmcontinue != "" ); |
|||
MatchCollection match2 = |
|||
new Regex("title=\"Category:(.+?)\">.+?</a>[^(]*\\(([\\d,.]+) members\\)").Matches(get2); |
|||
foreach (Match match in match2) |
|||
{ |
|||
if (langs.Contains(match.Groups[1].Value)) |
|||
{ |
|||
qtdmbr.Add(match.Groups[1].Value, Int32.Parse(match.Groups[2].Value |
|||
.Replace(",",string.Empty) |
|||
.Replace(".",string.Empty))); |
|||
} |
|||
} |
|||
string[] test = |
|||
qtdmbr.OrderByDescending(x => x.Value).Select(x => String.Format("{0,4} {1}", x.Value, x.Key)).ToArray(); |
|||
int count = 1; |
|||
foreach (string i in test) |
|||
{ |
|||
Console.WriteLine("{0,4}: {1}", count, i); |
|||
count++; |
|||
} |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out|Output (as of September 11, 2023)}} |
|||
<pre> |
|||
1: 1660 Phix |
|||
2: 1653 Wren |
|||
3: 1617 Julia |
|||
4: 1598 Raku |
|||
5: 1577 Nim |
|||
6: 1548 Go |
|||
7: 1537 Perl |
|||
8: 1487 Python |
|||
9: 1376 J |
|||
10: 1287 C |
|||
. . . |
|||
</pre> |
|||
===Object-oriented solution=== |
|||
<syntaxhighlight 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++; |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|C++}}== |
|||
{{libheader|Boost}} |
|||
using g++ under Linux with <tt>g++ -lboost_thread -lboost_system -lboost_regex</tt>: |
|||
<syntaxhighlight lang="cpp">#include <string> |
|||
#include <boost/regex.hpp> |
|||
#include <boost/asio.hpp> |
|||
#include <vector> |
|||
#include <utility> |
|||
#include <iostream> |
|||
#include <sstream> |
|||
#include <cstdlib> |
|||
#include <algorithm> |
|||
#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( "<li><a href=\"[^<>]+?\">([a-zA-Z\\+#1-9]+?)</a>\\s?\\((\\d+) members\\)</li>" ) ; |
|||
//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 ; |
|||
}</syntaxhighlight> |
|||
{{out|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 |
|||
=={{header|Caché ObjectScript}}== |
|||
<syntaxhighlight 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 |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out|Example}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|D}}== |
|||
With dmd you need compile like "<tt>dmd rosetta_popularity.d -L-lphobos2 -L-lcurl</tt>". |
|||
<syntaxhighlight 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[]); |
|||
}</syntaxhighlight> |
|||
{{out|Sample output (top twenty as of 2013-01-24)}} |
|||
<pre> 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</pre> |
|||
=={{header|Delphi}}== |
|||
{{libheader| System.SysUtils}} |
|||
{{libheader| System.Classes}} |
|||
{{libheader| IdHttp}} |
|||
{{libheader| IdBaseComponent}} |
|||
{{libheader| IdComponent}} |
|||
{{libheader| IdIOHandler}} |
|||
{{libheader| IdIOHandlerSocket}} |
|||
{{libheader| IdIOHandlerStack}} |
|||
{{libheader| IdSSL}} |
|||
{{libheader| IdSSLOpenSSL}} |
|||
{{libheader| System.RegularExpressions}} |
|||
{{libheader| System.Generics.Collections}} |
|||
{{libheader| System.Generics.Defaults}} |
|||
For safe run, download dlls: libeay32.dll & ssleay32.dll, then put in executable path. |
|||
<syntaxhighlight 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. |
|||
</syntaxhighlight> |
|||
{{out|Output (as of Jul 27, 2020)}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|Erlang}}== |
|||
<syntaxhighlight 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}. |
|||
</syntaxhighlight> |
|||
{{out|Sample output (top/last ten as of 2013-05-27)}} |
|||
<pre> |
|||
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" |
|||
</pre> |
</pre> |
||
=={{header|F_Sharp|F#}}== |
|||
Filtering wrong results is optional. You can check against http://www.rosettacode.org/wiki/Special:MostLinkedCategories |
|||
<syntaxhighlight 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</syntaxhighlight> |
|||
Showing top 20 as of 2013-04-02 |
|||
<pre> |
|||
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</pre> |
|||
=={{header|Go}}== |
|||
<syntaxhighlight 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("<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}) |
|||
} |
|||
} |
|||
} |
|||
// 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) |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out|Output on 11 Aug 2014}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
(All the final entries are tied for spot 506, there are 530 lines.) |
|||
=={{header|Groovy}}== |
|||
<syntaxhighlight 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 =~ '<li><a[^>]+>([^<]+)</a>[^(]*[(](\\d+) member[s]*[)]</li>').each { match, language, members -> |
|||
count[language] = (members as int) |
|||
} |
|||
count.sort { v1, v2 -> v2.value <=> v1.value }.eachWithIndex { value, index -> println "${index + 1} $value" }</syntaxhighlight> |
|||
Output: |
|||
<pre>1 Tcl=766 |
|||
2 Racket=726 |
|||
3 Python=712 |
|||
4 Programming Tasks=695 |
|||
5 C=681 |
|||
6 Perl 6=649 |
|||
... |
|||
48 Groovy=323</pre> |
|||
=={{header|Haskell}}== |
|||
===Haskell: Using the API=== |
|||
<syntaxhighlight 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</syntaxhighlight> |
|||
{{out}} |
|||
(As of 2015-07-29.) Here we show only the top 30. |
|||
<pre>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</pre> |
|||
===Haskell: Using web scraping=== |
|||
Scraping the languages and categories pages. |
|||
<syntaxhighlight 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 "<li>") $ 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</syntaxhighlight> |
|||
{{out|First 20}} |
|||
<pre>*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</pre> |
|||
=={{header|HicEst}}== |
|||
<syntaxhighlight 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) THEN |
|||
nr = nr + 1 |
|||
WRITE(Text=catlist, Format='i4, 1x, 2a', APPend) count, name, ';' |
|||
ENDIF |
|||
GOTO 1 ! no WHILE in HicEst |
|||
ENDIF ! catlist is now = " 1 ... User ; 2 100 doors ; 3 3D ; 8 4D ; ..." |
|||
ALLOCATE(RankNr, nr) |
|||
EDIT(Text=catlist, SePaRators=';', Option=1+4, SorTtoIndex=RankNr) ! case (1) and back (4) |
|||
sortedCat = ' ' ! get the sorted list in the sequence of RankNr: |
|||
ok = 0 |
|||
DO i = 1, nr |
|||
EDIT(Text=catlist, SePaRators=';', ITeM=RankNr(i), CoPyto=sample) |
|||
discard = EDIT(Text=sample, LeXicon='user,attention,solutions,tasks,program,language,implementation,') |
|||
IF(discard == 0) THEN ! removes many of the non-language entries |
|||
ok = ok + 1 |
|||
WRITE(Text=sortedCat, APPend, Format='F5.0, 2A') ok, TRIM(sample), $CRLF |
|||
ENDIF |
|||
ENDDO |
|||
DLG(Text=sortedCat, Format=$CRLF) |
|||
END</syntaxhighlight> |
|||
<syntaxhighlight lang="hicest">2010-04-24 18:31 |
|||
Top 10 entries (not all are languages) |
|||
1. 394 Tcl |
|||
2. 363 Python |
|||
3. 346 Ruby |
|||
4. 328 J |
|||
5. 319 C |
|||
6. 317 OCaml |
|||
7. 315 Haskell |
|||
8. 298 Perl |
|||
9. 288 WikiStubs |
|||
10. 281 Common Lisp</syntaxhighlight> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
|||
===By using the API=== |
|||
The following solution only works in Unicon. |
|||
<syntaxhighlight lang="unicon">$define RCLANGS "http://rosettacode.org/mw/api.php?format=xml&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo" |
|||
$define RCUA "User-Agent: Unicon Rosetta 0.1" |
|||
$define RCXUA "X-Unicon: http://unicon.org/" |
|||
link strings |
|||
link hexcvt |
|||
procedure main() |
|||
cnt := create seq() |
|||
last := -1 |
|||
every pair := !reverse(sort(langs := tallyPages(),2)) do { |
|||
n := if last ~=:= pair[2] then @cnt else (@cnt,"") |
|||
write(right(n,4),": ",left(pair[1],30,". "),right(pair[2],10,". ")) |
|||
} |
|||
write(*langs, " languages") |
|||
end |
|||
# Generate page counts for each language |
|||
procedure tallyPages(url) |
|||
/url := RCLANGS |
|||
counts := table() |
|||
continue := "" |
|||
while \(txt := ReadURL(url||continue)) do { |
|||
txt ? { |
|||
if tab(find("gcmcontinue=")) then { |
|||
continue := "&"||tab(upto('"')) |
|||
move(1) |
|||
continue ||:= tab(upto('"')) |
|||
} |
|||
else continue := "" |
|||
while tab(find("<page ") & find(s := "title=\"Category:")+*s) do { |
|||
lang := tab(upto('"')) |
|||
tab(find(s := "pages=\"")+*s) |
|||
counts[lang] := numeric(tab(upto('"'))) |
|||
} |
|||
if continue == "" then return counts |
|||
} |
|||
} |
|||
end |
|||
procedure ReadURL(url) #: read URL into string |
|||
page := open(url,"m",RCUA,RCXUA) | stop("Unable to open ",url) |
|||
text := "" |
|||
if page["Status-Code"] < 300 then while text ||:= reads(page,-1) |
|||
else write(&errout,image(url),": ", |
|||
page["Status-Code"]," ",page["Reason-Phrase"]) |
|||
close(page) |
|||
return text |
|||
end</syntaxhighlight> |
|||
Abridged output (top 26 languages as of July 30, 2016): |
|||
<pre> |
|||
1: Racket. . . . . . . . . . . . . . . .904 |
|||
2: Tcl . . . . . . . . . . . . . . . . .894 |
|||
3: Python. . . . . . . . . . . . . . . .867 |
|||
4: J . . . . . . . . . . . . . . . . . .852 |
|||
5: Perl 6. . . . . . . . . . . . . . . .824 |
|||
6: Ruby. . . . . . . . . . . . . . . . .796 |
|||
7: C . . . . . . . . . . . . . . . . . .777 |
|||
8: Go. . . . . . . . . . . . . . . . . .769 |
|||
9: Java. . . . . . . . . . . . . . . . .764 |
|||
10: D . . . . . . . . . . . . . . . . . .747 |
|||
11: REXX. . . . . . . . . . . . . . . . .743 |
|||
12: Perl. . . . . . . . . . . . . . . . .736 |
|||
13: Haskell . . . . . . . . . . . . . . .712 |
|||
: Zkl . . . . . . . . . . . . . . . . .712 |
|||
15: PicoLisp. . . . . . . . . . . . . . .695 |
|||
16: Mathematica . . . . . . . . . . . . .686 |
|||
17: Sidef . . . . . . . . . . . . . . . .632 |
|||
18: Ada . . . . . . . . . . . . . . . . .626 |
|||
19: C++ . . . . . . . . . . . . . . . . .619 |
|||
20: AutoHotkey. . . . . . . . . . . . . .603 |
|||
21: Unicon. . . . . . . . . . . . . . . .578 |
|||
22: Common Lisp . . . . . . . . . . . . .577 |
|||
23: Scala . . . . . . . . . . . . . . . .561 |
|||
24: BBC BASIC . . . . . . . . . . . . . .535 |
|||
25: C sharp . . . . . . . . . . . . . . .529 |
|||
26: Icon. . . . . . . . . . . . . . . . .520 |
|||
... |
|||
604 languages |
|||
</pre> |
|||
=={{header|J}}== |
|||
{{works with|J|6.02 (32 bit only)}} |
|||
'''Solution''':<syntaxhighlight lang="j">require 'web/gethttp xml/sax/x2j regex' |
|||
x2jclass 'rcPopLang' |
|||
rx =: (<0 1) {:: (2#a:) ,~ rxmatches rxfrom ] |
|||
'Popular Languages' x2jDefn |
|||
/ := langs : langs =: 0 2 $ a: |
|||
html/body/div/div/div/ul/li := langs =: langs ,^:(a:~:{.@[)~ lang ; ' \((\d+) members?\)' rx y |
|||
html/body/div/div/div/ul/li/a := lang =: '^\s*((?:.(?!User|Tasks|Omit|attention|operations|by))+)\s*$' rx y |
|||
) |
|||
cocurrent'base' |
|||
sortTab =. \: __ ". [: ;:^:_1: {:"1 |
|||
formatTab =: [: ;:^:_1: [: (20 A. (<'-') , |. , [: ('.' <"1@:,.~ ":) 1 + 1 i.@,~ 1{$)&.|: sortTab f. |
|||
rcPopLangs =: formatTab@:process_rcPopLang_@:gethttp</syntaxhighlight> |
|||
'''Example''':<syntaxhighlight lang="j"> 10 {. rcPopLangs 'http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=2000' |
|||
1. 687 - Tcl |
|||
2. 646 - Python |
|||
3. 637 - C |
|||
4. 626 - PicoLisp |
|||
5. 612 - J |
|||
6. 587 - Go |
|||
7. 556 - Ada |
|||
8. 550 - D |
|||
9. 549 - Mathematica |
|||
10. 526 - Perl</syntaxhighlight> |
|||
'''Notes''': See some [[Talk:Sort most popular programming languages#J|notes on the J solution]]. |
|||
=={{header|Java}}== |
|||
Tested with Java 1.22. Uses the api.<br/> |
|||
<syntaxhighlight lang="java"> |
|||
import java.net.URI; |
|||
import java.net.URL; |
|||
import java.net.URLConnection; |
|||
import java.io.*; |
|||
import java.util.*; |
|||
public class GetRCLanguages |
|||
{ |
|||
// Custom sort Comparator for sorting the language list |
|||
// assumes the first character is the page count and the rest is the language name |
|||
private static class LanguageComparator implements Comparator<String> |
|||
{ |
|||
public int compare( String a, String b ) |
|||
{ |
|||
// as we "know" we will be comparaing languages, we will assume the Strings have the appropriate format |
|||
int result = ( b.charAt( 0 ) - a.charAt( 0 ) ); |
|||
if( result == 0 ) |
|||
{ |
|||
// the counts are the same - compare the names |
|||
result = a.compareTo( b ); |
|||
} // if result == 0 |
|||
return result; |
|||
} // compare |
|||
} // LanguageComparator |
|||
// get the string following marker in text |
|||
private static String after( String text, int marker ) |
|||
{ |
|||
String result = ""; |
|||
int pos = text.indexOf( marker ); |
|||
if( pos >= 0 ) |
|||
{ |
|||
// the marker is in the string |
|||
result = text.substring( pos + 1 ); |
|||
} // if pos >= 0 |
|||
return result; |
|||
} // after |
|||
// read and parse the content of path |
|||
// results returned in gcmcontinue and languageList |
|||
public static void parseContent( String path |
|||
, String[] gcmcontinue |
|||
, ArrayList<String> languageList |
|||
) |
|||
{ |
|||
try |
|||
{ |
|||
URL url = new URI( path ).toURL(); |
|||
URLConnection rc = url.openConnection(); |
|||
BufferedReader bfr = new BufferedReader( new InputStreamReader( rc.getInputStream() ) ); |
|||
gcmcontinue[0] = ""; |
|||
String languageName = "?"; |
|||
String line = bfr.readLine(); |
|||
while( line != null ) |
|||
{ |
|||
line = line.trim().replaceAll( "[\",]", "" ); |
|||
if ( line.startsWith( "title" ) ) |
|||
{ |
|||
// have a programming language - should look like "title: Category:languageName" |
|||
languageName = after( after( line, ':' ), ':' ).trim(); |
|||
} |
|||
else if( line.startsWith( "pages" ) ) |
|||
{ |
|||
// number of pages the language has (probably) |
|||
String pageCount = after( line, ':' ).trim(); |
|||
if( pageCount.compareTo( "{" ) != 0 ) |
|||
{ |
|||
// haven't got "pages: {" - must be a number of pages |
|||
languageList.add( ( (char) Integer.parseInt( pageCount ) ) + languageName ); |
|||
languageName = "?"; |
|||
} // if [pageCount.compareTo( "{" ) != 0 |
|||
} |
|||
else if( line.startsWith( "gcmcontinue" ) ) |
|||
{ |
|||
// have an indication of wether there is more data or not |
|||
gcmcontinue[0] = after( line, ':' ).trim().replaceAll( "[|]", "%7C" ); |
|||
} // if various line starts |
|||
line = bfr.readLine(); |
|||
} // while line != null |
|||
bfr.close(); |
|||
} |
|||
catch( Exception e ) |
|||
{ |
|||
e.printStackTrace(); |
|||
} // try-catch |
|||
} // parseContent |
|||
public static void main( String[] args ) |
|||
{ |
|||
// get the languages |
|||
ArrayList<String> languageList = new ArrayList<String>( 1000 ); |
|||
String[] gcmcontinue = new String[1]; |
|||
gcmcontinue[0] = ""; |
|||
do |
|||
{ |
|||
String path = ( "https://www.rosettacode.org/w/api.php?action=query" |
|||
+ "&generator=categorymembers" |
|||
+ "&gcmtitle=Category:Programming%20Languages" |
|||
+ "&gcmlimit=500" |
|||
+ ( gcmcontinue[0].compareTo( "" ) == 0 ? "" : ( "&gcmcontinue=" + gcmcontinue[0] ) ) |
|||
+ "&prop=categoryinfo" |
|||
+ "&format=jsonfm" |
|||
); |
|||
parseContent( path, gcmcontinue, languageList ); |
|||
} |
|||
while( gcmcontinue[0].compareTo( "" ) != 0 ); |
|||
// sort the languages |
|||
String[] languages = languageList.toArray(new String[]{}); |
|||
Arrays.sort( languages, new LanguageComparator() ); |
|||
// print the languages |
|||
int lastTie = -1; |
|||
int lastCount = -1; |
|||
for( int lPos = 0; lPos < languages.length; lPos ++ ) |
|||
{ |
|||
int count = (int) ( languages[ lPos ].charAt( 0 ) ); |
|||
System.out.format( "%4d: %4d: %s\n" |
|||
, 1 + ( count == lastCount ? lastTie : lPos ) |
|||
, count |
|||
, languages[ lPos ].substring( 1 ) |
|||
); |
|||
if( count != lastCount ) |
|||
{ |
|||
lastTie = lPos; |
|||
lastCount = count; |
|||
} // if count != lastCount |
|||
} // for lPos |
|||
} // main |
|||
} // GetRCLanguages |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
Top 10 languages as at 1st June 2024 |
|||
<pre> |
|||
1: 1675: Phix |
|||
1: 1675: Wren |
|||
3: 1650: Julia |
|||
4: 1620: Raku |
|||
5: 1576: Nim |
|||
6: 1549: Go |
|||
7: 1542: Perl |
|||
8: 1514: Python |
|||
9: 1413: J |
|||
10: 1346: Java |
|||
... |
|||
</pre> |
|||
=={{header|jq}}== |
|||
{{works with|jq|1.4}} |
|||
The following solution matches the languages listed on the Category:Programming_Languages page with the statistics given on the Special:Categories page, making an adjustment for the number of irrelevant subcategories. |
|||
jq 1.4 cannot retrieve documents over the web and has no support for regular expressions, but is intended to work seamlessly with other command line tools, so the following solution is presented in the form of a bash script that uses curl for retrieval, and grep and sed for screen scraping. |
|||
<syntaxhighlight lang="sh">#!/bin/bash |
|||
# produce lines of the form: [ "language", n ] |
|||
function categories { |
|||
curl -Ss 'http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000' |\ |
|||
grep "/wiki/Category:" | grep member | grep -v '(.*(' |\ |
|||
grep -v ' User</a>' |\ |
|||
sed -e 's/.*title="Category://' -e 's/member.*//' |\ |
|||
sed 's:^\([^"]*\)"[^(]*(\(.*\):["\1", \2]:' |
|||
} |
|||
# produce lines of the form: "language" |
|||
function languages { |
|||
curl -Ss 'http://rosettacode.org/wiki/Category:Programming_Languages' |\ |
|||
sed '/Pages in category "Programming Languages"/,$d' |\ |
|||
grep '<li><a href="/wiki/Category:' | fgrep title= |\ |
|||
sed 's/.*Category:\([^"]*\)".*/"\1"/' |
|||
} |
|||
categories |\ |
|||
/usr/local/bin/jq --argfile languages <(languages) -s -r ' |
|||
# input: array of [score, _] sorted by score |
|||
# output: array of [ranking, score, _] |
|||
def ranking: |
|||
reduce .[] as $x |
|||
([]; # array of [count, rank, score, _] |
|||
if length == 0 then [[1, 1] + $x] |
|||
else .[length - 1] as $previous |
|||
| if $x[0] == $previous[2] |
|||
then . + [ [$previous[0] + 1, $previous[1]] + $x ] |
|||
else . + [ [$previous[0] + 1, $previous[0] + 1] + $x ] |
|||
end |
|||
end) |
|||
| [ .[] | .[1:] ]; |
|||
# Every language page has three category pages that should be excluded |
|||
(reduce .[] as $pair |
|||
({}; |
|||
($pair[1] as $n | if $n > 3 then . + {($pair[0]): ($n - 3)} else . end ))) as $freq |
|||
| [ $languages[] | select($freq[.] != null) | [$freq[.], .]] |
|||
| sort |
|||
| reverse |
|||
| ranking[] |
|||
| "\(.[0]). \(.[1]) - \(.[2])" '</syntaxhighlight> |
|||
{{out}} |
|||
<syntaxhighlight lang="sh"># First ten and last ten lines as of May 27, 2015 |
|||
$ pop.sh |
|||
1. 868 - Tcl |
|||
2. 863 - Racket |
|||
3. 842 - Python |
|||
4. 778 - J |
|||
5. 769 - Ruby |
|||
6. 756 - Perl 6 |
|||
7. 752 - C |
|||
8. 736 - D |
|||
9. 735 - Go |
|||
10. 700 - Perl |
|||
... |
|||
386. 1 - FP |
|||
386. 1 - ElastiC |
|||
386. 1 - ESQL |
|||
386. 1 - Clipper/XBase++ |
|||
386. 1 - Bori |
|||
386. 1 - Biferno |
|||
386. 1 - AspectJ |
|||
386. 1 - Algae |
|||
386. 1 - 80386 Assembly |
|||
386. 1 - 68000 Assembly</syntaxhighlight> |
|||
=={{header|Julia}}== |
|||
Uses the API for the language list and page scraping for the example counts for each language. |
|||
<syntaxhighlight lang="julia">""" Rosetta code task rosettacode.org/wiki/Rosetta_Code/Rank_languages_by_popularity """ |
|||
using Dates |
|||
using DataFrames |
|||
using HTTP |
|||
using JSON3 |
|||
""" Get listing of all tasks and draft tasks with authors and dates created, with the counts as popularity """ |
|||
function rosetta_code_language_example_counts(verbose = false) |
|||
URL = "https://rosettacode.org/w/api.php?" |
|||
LANGPARAMS = ["action" => "query", "format" => "json", "formatversion" => "2", "generator" => "categorymembers", |
|||
"gcmtitle" => "Category:Programming_Languages", "gcmlimit" => "500", "rawcontinue" => "", "prop" => "title"] |
|||
queryparams = copy(LANGPARAMS) |
|||
df = empty!(DataFrame([[""], [0]], ["ProgrammingLanguage", "ExampleCount"])) |
|||
while true # get all the languages listed, with curid, eg rosettacode.org/w/index.php?curid=196 for C |
|||
resp = HTTP.get(URL * join(map(p -> p[1] * (p[2] == "" ? "" : ("=" * p[2])), queryparams), "&")) |
|||
json = JSON3.read(String(resp.body)) |
|||
pages = json.query.pages |
|||
reg = r"The following \d+ pages are in this category, out of ([\d\,]+) total" |
|||
for p in pages |
|||
lang = replace(p.title, "Category:" => "") |
|||
langpage = String(HTTP.get("https://rosettacode.org/w/index.php?curid=" * string(p.pageid)).body) |
|||
if !((m = match(reg, langpage)) isa Nothing) |
|||
push!(df, [lang, parse(Int, replace(m.captures[1], "," => ""))]) |
|||
verbose && println("Language: $lang, count: ", m.captures[1]) |
|||
end |
|||
end |
|||
!haskey(json, "query-continue") && break # break if no more pages, else continue to next pages |
|||
queryparams = vcat(LANGPARAMS, "gcmcontinue" => json["query-continue"]["categorymembers"]["gcmcontinue"]) |
|||
end |
|||
return sort!(df, :ExampleCount, rev = true) |
|||
end |
|||
println("Top 20 Programming Languages on Rosetta Code by Number of Examples, As of: ", now()) |
|||
println(rosetta_code_language_example_counts()[begin:begin+19, :]) |
|||
</syntaxhighlight>{{out}} |
|||
<pre> |
|||
Top 20 Programming Languages on Rosetta Code by Number of Examples, As of: 2022-09-05T14:59:56.316 |
|||
20×2 DataFrame |
|||
Row │ ProgrammingLanguage ExampleCount |
|||
│ String Int64 |
|||
─────┼─────────────────────────────────── |
|||
1 │ Wren 1569 |
|||
2 │ Phix 1569 |
|||
3 │ Julia 1537 |
|||
4 │ Raku 1517 |
|||
5 │ Go 1496 |
|||
6 │ Perl 1460 |
|||
7 │ Python 1404 |
|||
8 │ Nim 1402 |
|||
9 │ J 1275 |
|||
10 │ C 1210 |
|||
11 │ Mathematica 1178 |
|||
12 │ REXX 1149 |
|||
13 │ Haskell 1139 |
|||
14 │ Java 1136 |
|||
15 │ Kotlin 1133 |
|||
16 │ C++ 1120 |
|||
17 │ Ruby 1103 |
|||
18 │ Racket 1089 |
|||
19 │ FreeBASIC 1069 |
|||
20 │ Zkl 1011 |
|||
</pre> |
|||
=={{header|Kotlin}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="scala">import java.net.URL |
|||
import java.io.* |
|||
object Popularity { |
|||
/** Gets language data. */ |
|||
fun ofLanguages(): List<String> { |
|||
val languages = mutableListOf<String>() |
|||
var gcm = "" |
|||
do { |
|||
val path = url + (if (gcm == "") "" else "&gcmcontinue=" + gcm) + "&prop=categoryinfo" + "&format=txt" |
|||
try { |
|||
val rc = URL(path).openConnection() // URL completed, connection opened |
|||
// Rosetta Code objects to the default Java user agent so use a blank one |
|||
rc.setRequestProperty("User-Agent", "") |
|||
val bfr = BufferedReader(InputStreamReader(rc.inputStream)) |
|||
try { |
|||
gcm = "" |
|||
var languageName = "?" |
|||
var line: String? = bfr.readLine() |
|||
while (line != null) { |
|||
line = line.trim { it <= ' ' } |
|||
if (line.startsWith("[title]")) { |
|||
// have a programming language - should look like "[title] => Category:languageName" |
|||
languageName = line[':'] |
|||
} else if (line.startsWith("[pages]")) { |
|||
// number of pages the language has (probably) |
|||
val pageCount = line['>'] |
|||
if (pageCount != "Array") { |
|||
// haven't got "[pages] => Array" - must be a number of pages |
|||
languages += pageCount.toInt().toChar() + languageName |
|||
languageName = "?" |
|||
} |
|||
} else if (line.startsWith("[gcmcontinue]")) |
|||
gcm = line['>'] // have an indication of whether there is more data or not |
|||
line = bfr.readLine() |
|||
} |
|||
} finally { |
|||
bfr.close() |
|||
} |
|||
} catch (e: Exception) { |
|||
e.printStackTrace() |
|||
} |
|||
} while (gcm != "") |
|||
return languages.sortedWith(LanguageComparator) |
|||
} |
|||
/** Custom sort Comparator for sorting the language list. |
|||
* Assumes the first character is the page count and the rest is the language name. */ |
|||
internal object LanguageComparator : java.util.Comparator<String> { |
|||
override fun compare(a: String, b: String): Int { |
|||
// as we "know" we will be comparing languages, we will assume the Strings have the appropriate format |
|||
var r = b.first() - a.first() |
|||
return if (r == 0) a.compareTo(b) else r |
|||
// r == 0: the counts are the same - compare the names |
|||
} |
|||
} |
|||
/** Gets the string following marker in text. */ |
|||
private operator fun String.get(c: Char) = substringAfter(c).trim { it <= ' ' } |
|||
private val url = "http://www.rosettacode.org/mw/api.php?action=query" + |
|||
"&generator=categorymembers" + "&gcmtitle=Category:Programming%20Languages" + |
|||
"&gcmlimit=500" |
|||
} |
|||
fun main(args: Array<String>) { |
|||
// read/sort/print the languages (CSV format): |
|||
var lastTie = -1 |
|||
var lastCount = -1 |
|||
Popularity.ofLanguages().forEachIndexed { i, lang -> |
|||
val count = lang.first().toInt() |
|||
if (count == lastCount) |
|||
println("%12s%s".format("", lang.substring(1))) |
|||
else { |
|||
println("%4d, %4d, %s".format(1 + if (count == lastCount) lastTie else i, count, lang.substring(1))) |
|||
lastTie = i |
|||
lastCount = count |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1, 901, Racket |
|||
2, 893, Tcl |
|||
3, 851, Python |
|||
4, 826, J |
|||
5, 796, Perl 6 |
|||
... |
|||
135, 70, Kotlin |
|||
...</pre> |
|||
=={{header|Lasso}}== |
|||
<syntaxhighlight lang="lasso"><pre><code>[ |
|||
sys_listtraits !>> 'xml_tree_trait' ? include('xml_tree.lasso') |
|||
local(lang = array) |
|||
local(f = curl('http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000')->result->asString) |
|||
local(ff) = xml_tree(#f) |
|||
local(lis = #ff->body->div(3)->div(3)->div(3)->div->ul->getnodes) |
|||
with li in #lis do => { |
|||
local(title = #li->a->attribute('title')) |
|||
#title->removeLeading('Category:') |
|||
local(num = #li->asString->split('(')->last) |
|||
#num->removeTrailing(')') |
|||
#num->removeTrailing('members') |
|||
#num->removeTrailing('member') |
|||
#num->trim |
|||
#num = integer(#num) |
|||
#lang->insert(#title = #num) |
|||
} |
|||
local(c = 1) |
|||
with l in #lang |
|||
order by #l->second descending |
|||
do => {^ |
|||
#c++ |
|||
'. '+#l->second + ' - ' + #l->first+'\r' |
|||
^} |
|||
]</code></pre></syntaxhighlight> |
|||
{{out}} |
|||
<pre>1. 759 - Tcl |
|||
2. 724 - Racket |
|||
3. 707 - Python |
|||
4. 692 - Programming Tasks |
|||
5. 672 - C |
|||
6. 643 - J |
|||
7. 635 - Perl 6 |
|||
8. 632 - D |
|||
9. 627 - PicoLisp |
|||
10. 617 - Ruby |
|||
...</pre> |
|||
=={{header|M2000 Interpreter}}== |
|||
Based on BBC BASIC idea, and using M2000 Rinstr() and objects as Inventories, Document, and Microsoft.XMLHTTP for downloading (async use). Results also copy to Clipboard. We can use Msxml2.ServerXMLHTTP (code is the same, only name of object change). |
|||
Update: Numbers above 999 get a comma (,) so we have to drop this using Filter$() |
|||
<syntaxhighlight lang="m2000 interpreter"> |
|||
Module RankLanguages { |
|||
Const Part1$="<a href="+""""+ "/wiki/Category", Part2$="member" |
|||
Const langHttp$="http://rosettacode.org/wiki/Category:Programming_Languages" |
|||
Const categoriesHttp$="http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000" |
|||
Def long m, i,j, tasks, counter, limit, T, t1 |
|||
Def string LastLang$, job$ |
|||
Document final$, languages$, categories$ |
|||
httpGet$=lambda$ (url$, timeout=1000)->{ |
|||
Declare htmldoc "Msxml2.ServerXMLHTTP" |
|||
With htmldoc , "readyState" as ready |
|||
Report "Download:"+url$ |
|||
Method htmldoc "open","get", url$, True |
|||
Method htmldoc "send" |
|||
Profiler |
|||
While Ready<>4 { |
|||
Wait 20 |
|||
Print Over format$("Wait: {0:3} sec", timecount/1000) |
|||
If timecount>timeout then Exit |
|||
} |
|||
If ready=4 Then With htmldoc, "responseText" as ready$ : =ready$ |
|||
Declare htmldoc Nothing |
|||
print |
|||
} |
|||
languages$=httpGet$(langHttp$, 30000) |
|||
If Doc.Len(languages$)=0 then Error "File download failed (languages)" |
|||
Inventory Lang |
|||
m=Paragraph(languages$, 0) |
|||
If Forward(languages$,m) then { |
|||
While m { |
|||
job$=Paragraph$(languages$,(m)) |
|||
If Instr(job$, part1$) Else Continue |
|||
i = Instr(job$, "</a>") |
|||
If i Else Continue ' same as If i=0 Then Continue |
|||
j = i |
|||
i=Rinstr(job$, ">", -i) |
|||
If i Else Continue |
|||
LastLang$=MID$(job$, i+1, j-i-1) |
|||
if Instr(job$, "Category:"+lastlang$) then Append lang, lastlang$:=0 : Print Over format$("Languages: {0}", len(lang)) |
|||
} |
|||
} |
|||
Print |
|||
Document categories$=httpGet$(categoriesHttp$, 30000) |
|||
If Doc.Len(categories$)=0 then Error "File download failed (categories)" |
|||
limit=Doc.Par(categories$) |
|||
If limit<Len(Lang) then Error "Invalid data" |
|||
Refresh |
|||
set slow |
|||
m=Paragraph(categories$, 0) |
|||
counter=0 |
|||
If Forward(categories$,m) then { |
|||
While m { |
|||
job$=Paragraph$(categories$,(m)) |
|||
counter++ |
|||
Print Over format$("{0:2:-6}%", counter/limit*100) |
|||
i=Instr(job$, part2$) |
|||
If i Else Continue |
|||
i=Rinstr(job$, "(", -i) |
|||
If i Else Continue |
|||
tasks=Val(Filter$(Mid$(job$, i+1),",")) |
|||
If tasks Else Continue |
|||
i=Rinstr(job$, "<", -i) |
|||
If i Else Continue |
|||
j = i |
|||
i=Rinstr(job$, ">", -i) |
|||
If i Else Continue |
|||
LastLang$=MID$(job$, i+1, j-i-1) |
|||
If Exist(Lang, LastLang$) Then { |
|||
Return Lang, LastLang$:=Lang(LastLang$)+tasks |
|||
} |
|||
} |
|||
} |
|||
Print |
|||
\\ this type of inventory can get same keys |
|||
\\ also has stable sort |
|||
Report "Make Inventory list by Task" |
|||
Inventory queue ByTask |
|||
t1=Len(Lang) |
|||
T=Each(Lang) |
|||
While T { |
|||
Append ByTask, Eval(T):=Eval$(T!) |
|||
Print Over format$("Complete: {0} of {1}", T^+1, t1 ) |
|||
} |
|||
Print |
|||
Report "Sort by task (stable sort, sort keys as numbers)" |
|||
Sort descending ByTask as number |
|||
Report "Make List" |
|||
T=Each(ByTask) |
|||
final$="Sample output on "+Date$(Today, 1033, "long date")+{: |
|||
} |
|||
While T { |
|||
final$=format$("rank:{0::-4}. {1:-5} entries - {2}", T^+1, Eval$(T!), Eval$(T))+{ |
|||
} |
|||
} |
|||
Report "Copy to Clipboard" |
|||
clipboard final$ |
|||
\\ present to console with 3/4 fill lines then stop for space bar or mouse click to continue |
|||
Report final$ |
|||
} |
|||
RankLanguages |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre style="height:30ex;overflow:scroll"> |
|||
Sample output on Saturday, June 22, 2019: |
|||
rank: 1. 1149 entries - Go |
|||
rank: 2. 1084 entries - Perl 6 |
|||
rank: 3. 1061 entries - Python |
|||
rank: 4. 1045 entries - Kotlin |
|||
rank: 5. 1044 entries - Julia |
|||
rank: 6. 1033 entries - Phix |
|||
rank: 7. 1026 entries - Perl |
|||
rank: 8. 991 entries - Racket |
|||
rank: 9. 951 entries - C |
|||
rank: 10. 944 entries - J |
|||
rank: 11. 938 entries - Zkl |
|||
rank: 12. 930 entries - Tcl |
|||
rank: 13. 910 entries - REXX |
|||
rank: 14. 909 entries - Java |
|||
rank: 15. 883 entries - Ruby |
|||
rank: 16. 881 entries - D |
|||
rank: 17. 869 entries - Haskell |
|||
rank: 18. 814 entries - Sidef |
|||
rank: 19. 801 entries - Scala |
|||
rank: 20. 779 entries - C sharp |
|||
rank: 21. 775 entries - PicoLisp |
|||
rank: 22. 772 entries - C++ |
|||
rank: 23. 748 entries - Mathematica |
|||
rank: 24. 678 entries - Common Lisp |
|||
rank: 25. 668 entries - Ada |
|||
rank: 26. 639 entries - JavaScript |
|||
rank: 27. 633 entries - Lua |
|||
rank: 28. 628 entries - AutoHotkey |
|||
rank: 29. 611 entries - Ring |
|||
rank: 30. 595 entries - Factor |
|||
rank: 31. 594 entries - Clojure |
|||
rank: 32. 590 entries - Unicon |
|||
rank: 33. 566 entries - ALGOL 68 |
|||
rank: 34. 563 entries - Nim |
|||
rank: 35. 563 entries - PureBasic |
|||
rank: 36. 560 entries - BBC BASIC |
|||
rank: 37. 559 entries - Fortran |
|||
rank: 38. 556 entries - OCaml |
|||
rank: 39. 540 entries - PARI/GP |
|||
rank: 40. 538 entries - F Sharp |
|||
rank: 41. 532 entries - Icon |
|||
rank: 42. 517 entries - Elixir |
|||
rank: 43. 497 entries - FreeBASIC |
|||
rank: 44. 495 entries - Erlang |
|||
rank: 45. 485 entries - Rust |
|||
rank: 46. 473 entries - PowerShell |
|||
rank: 47. 462 entries - Jq |
|||
rank: 48. 456 entries - Pascal |
|||
rank: 49. 453 entries - AWK |
|||
rank: 50. 450 entries - Forth |
|||
rank: 51. 448 entries - Seed7 |
|||
rank: 52. 435 entries - R |
|||
rank: 53. 414 entries - Groovy |
|||
rank: 54. 403 entries - PL/I |
|||
rank: 55. 401 entries - PHP |
|||
rank: 56. 383 entries - VBA |
|||
rank: 57. 361 entries - Scheme |
|||
rank: 58. 359 entries - MATLAB |
|||
rank: 59. 353 entries - Swift |
|||
rank: 60. 346 entries - M2000 Interpreter |
|||
rank: 61. 343 entries - Maple |
|||
rank: 62. 337 entries - Liberty BASIC |
|||
rank: 63. 314 entries - Run BASIC |
|||
rank: 64. 309 entries - Prolog |
|||
.......... |
|||
rank: 685. 1 entries - Jacquard Loom |
|||
rank: 686. 1 entries - Kamailio Script |
|||
rank: 687. 1 entries - Lambda Prolog |
|||
rank: 688. 1 entries - LibreOffice Basic |
|||
rank: 689. 1 entries - MAPPER |
|||
rank: 690. 1 entries - MEL |
|||
rank: 691. 1 entries - MiniZinc |
|||
rank: 692. 1 entries - Mond |
|||
rank: 693. 1 entries - Monkey |
|||
rank: 694. 1 entries - NASL |
|||
rank: 695. 1 entries - Neat |
|||
rank: 696. 1 entries - NewtonScript |
|||
rank: 697. 1 entries - Nickle |
|||
rank: 698. 1 entries - Nix |
|||
rank: 699. 1 entries - Opa |
|||
rank: 700. 1 entries - Pare |
|||
rank: 701. 1 entries - Qore |
|||
rank: 702. 1 entries - Rapira |
|||
rank: 703. 1 entries - RPGIV |
|||
rank: 704. 1 entries - Setl4 |
|||
rank: 705. 1 entries - Soar |
|||
rank: 706. 1 entries - SoneKing Assembly |
|||
rank: 707. 1 entries - Supernova |
|||
rank: 708. 1 entries - SuperTalk |
|||
rank: 709. 1 entries - Terra |
|||
rank: 710. 1 entries - TestML |
|||
rank: 711. 1 entries - WebAssembly |
|||
rank: 712. 1 entries - Wollok |
|||
rank: 713. 1 entries - Xanadu |
|||
rank: 714. 1 entries - Ya |
|||
rank: 715. 1 entries - МiniZinc |
|||
rank: 716. 0 entries - AngelScript |
|||
rank: 717. 0 entries - Binary Lambda Calculus |
|||
rank: 718. 0 entries - EhBASIC |
|||
rank: 719. 0 entries - Epigram |
|||
rank: 720. 0 entries - FLORA-2 |
|||
rank: 721. 0 entries - Florid |
|||
rank: 722. 0 entries - Gerbil |
|||
rank: 723. 0 entries - LC2200 Assembly |
|||
rank: 724. 0 entries - Leon |
|||
rank: 725. 0 entries - Livecode |
|||
rank: 726. 0 entries - LLP |
|||
rank: 727. 0 entries - Loglan82 |
|||
rank: 728. 0 entries - Lolli |
|||
rank: 729. 0 entries - Lygon |
|||
rank: 730. 0 entries - ObjectIcon |
|||
rank: 731. 0 entries - PL/B |
|||
rank: 732. 0 entries - Plan |
|||
rank: 733. 0 entries - Reduce |
|||
rank: 734. 0 entries - Rubylog |
|||
rank: 735. 0 entries - S BASIC |
|||
rank: 736. 0 entries - SimpleLang |
|||
rank: 737. 0 entries - Star |
|||
rank: 738. 0 entries - X10 |
|||
rank: 739. 0 entries - XS |
|||
</pre > |
|||
=={{header|Maple}}== |
|||
<syntaxhighlight lang="maple">count_sizes := proc(arr_name,arr_pop,i,lst) |
|||
local index := i; |
|||
local language; |
|||
for language in lst do |
|||
language := language[1]: |
|||
arr_name(index) := txt["query"]["pages"][language]["title"][10..]: |
|||
if(assigned(txt["query"]["pages"][language]["categoryinfo"]["size"])) then |
|||
arr_pop(index) := txt["query"]["pages"][language]["categoryinfo"]["size"]: |
|||
else: |
|||
arr_pop(index) := 0: |
|||
end if: |
|||
index++: |
|||
end do: |
|||
return index: |
|||
end proc: |
|||
txt := JSON:-ParseFile("http://rosettacode.org/mw/api.php?action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=350&prop=categoryinfo&format=json"): |
|||
arr_name := Array(): |
|||
arr_pop := Array(): |
|||
i := count_sizes(arr_name, arr_pop, 1, [indices(txt["query"]["pages"])]): |
|||
while (assigned(txt["continue"]["gcmcontinue"])) do |
|||
continue := txt["continue"]["gcmcontinue"]: |
|||
txt := JSON:-ParseFile(cat("http://rosettacode.org/mw/api.php?action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=350&prop=categoryinfo&format=json", "&continue=", txt["continue"]["continue"], "&gcmcontinue=", txt["continue"]["gcmcontinue"])): |
|||
i:=count_sizes(arr_name,arr_pop,i,[indices(txt["query"]["pages"])]): |
|||
end do: |
|||
arr_name:= arr_name[sort(arr_pop,output=permutation)]: |
|||
arr_pop := sort(arr_pop, output=sorted): |
|||
i := i-1: |
|||
for x from i to 1 by -1 do |
|||
printf("rank %d %d examples %s\n", i-x+1, arr_pop[x], arr_name[x]): |
|||
end do:</syntaxhighlight> |
|||
{{Out|Output}} |
|||
<pre>#10:30 AM 10/05/2018 |
|||
rank 1 1002 examples Kotlin |
|||
rank 2 977 examples Racket |
|||
rank 3 977 examples Python |
|||
rank 4 949 examples Perl 6 |
|||
rank 5 918 examples Tcl |
|||
rank 6 898 examples C |
|||
rank 7 891 examples J |
|||
rank 8 879 examples Zkl |
|||
rank 9 870 examples Java |
|||
rank 10 860 examples D |
|||
... |
|||
rank 680 0 examples Epigram |
|||
rank 681 0 examples LLP |
|||
rank 682 0 examples Lolli |
|||
rank 683 0 examples Leon |
|||
rank 684 0 examples Florid |
|||
rank 685 0 examples Loglan82</pre> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">Languages = Flatten[Import["http://rosettacode.org/wiki/Category:Programming_Languages","Data"][[1,1]]]; |
|||
Languages = Most@StringReplace[Languages, {" " -> "_", "+" -> "%2B"}]; |
|||
b = {#, If[# === {}, 0, #[[1]]]&@( StringCases[Import["http://rosettacode.org/wiki/Category:"<>#,"Plaintext"], |
|||
"category, out of " ~~ x:NumberString ~~ " total" ->x])} &/@ Languages; |
|||
For[i = 1, i < Length@b , i++ , Print[i, ". ", #[[2]], " - ", #[[1]] ]&@ Part[Reverse@SortBy[b, Last], i]]</syntaxhighlight> |
|||
{{out|Output : As of 29 February 2012}} |
|||
<pre> |
|||
1. 637 - Tcl |
|||
2. 576 - C |
|||
3. 558 - J |
|||
4. 538 - Go |
|||
5. 485 - Ada |
|||
6. 456 - D |
|||
7. 450 - Haskell |
|||
8. 441 - Mathematica |
|||
9. 432 - Java |
|||
10. 425 - Icon |
|||
...</pre> |
|||
=={{header|Nim}}== |
|||
<syntaxhighlight lang="nim">import std/[Algorithm, httpclient, json, re, strformat, strutils] |
|||
const |
|||
LangSite = "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=500&format=json" |
|||
CatSite = "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000" |
|||
let regex = re"title=""Category:(.*?)"">.+?</a>.*\((.*) members\)" |
|||
type Rank = tuple[lang: string, count: int] |
|||
proc cmp(a, b: Rank): int = |
|||
result = cmp(b.count, a.count) |
|||
if result == 0: result = cmp(a.lang, b.lang) |
|||
proc add(langs: var seq[string]; fromJson: JsonNode) = |
|||
for entry in fromJson{"query", "categorymembers"}: |
|||
let title = entry["title"].getStr() |
|||
if title.startsWith("Category:"): |
|||
langs.add title[9..^1] |
|||
var client = newHttpClient() |
|||
var langs: seq[string] |
|||
var url = LangSite |
|||
while true: |
|||
let response = client.get(url) |
|||
if response.status != $Http200: break |
|||
let fromJson = response.body.parseJson() |
|||
langs.add fromJson |
|||
if "continue" notin fromJson: break |
|||
let cmcont = fromJson{"continue", "cmcontinue"}.getStr |
|||
let cont = fromJson{"continue", "continue"}.getStr |
|||
url = LangSite & fmt"&cmcontinue={cmcont}&continue={cont}" |
|||
var ranks: seq[Rank] |
|||
for line in client.getContent(CatSite).findAll(regex): |
|||
let lang = line.replacef(regex, "$1") |
|||
if lang in langs: |
|||
let count = parseInt(line.replacef(regex, "$2").replace(",", "").strip()) |
|||
ranks.add (lang, count) |
|||
ranks.sort(cmp) |
|||
for i, rank in ranks: |
|||
echo &"{i + 1:3} {rank.count:4} - {rank.lang}" |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre> 1 1626 - Phix |
|||
2 1620 - Wren |
|||
3 1587 - Julia |
|||
4 1574 - Raku |
|||
5 1533 - Go |
|||
6 1520 - Perl |
|||
7 1466 - Python |
|||
8 1430 - Nim |
|||
9 1348 - J |
|||
10 1264 - C |
|||
11 1198 - Ruby |
|||
12 1185 - Mathematica |
|||
13 1164 - Java |
|||
14 1160 - Haskell |
|||
15 1155 - C++ |
|||
16 1153 - REXX |
|||
17 1136 - Kotlin |
|||
18 1131 - FreeBASIC |
|||
19 1100 - Racket |
|||
20 1027 - Jq |
|||
21 1014 - 11l |
|||
22 1012 - Zkl |
|||
23 1004 - Sidef |
|||
24 997 - Factor |
|||
25 987 - D |
|||
26 980 - Tcl |
|||
27 938 - Ada |
|||
28 926 - C sharp |
|||
29 923 - Scala |
|||
30 906 - ALGOL 68 |
|||
31 896 - Rust |
|||
32 893 - Lua |
|||
33 849 - PicoLisp |
|||
34 843 - F Sharp |
|||
35 824 - AutoHotkey |
|||
36 818 - Ring |
|||
37 793 - Delphi |
|||
38 785 - JavaScript |
|||
39 778 - Arturo |
|||
40 776 - XPL0 |
|||
...</pre> |
|||
=={{header|Objeck}}== |
|||
<syntaxhighlight lang="objeck">use HTTP; |
|||
use RegEx; |
|||
use XML; |
|||
use Collection; |
|||
class RosettaRank { |
|||
function : Main(args : String[]) ~ Nil { |
|||
langs_xml := ""; |
|||
client := HttpClient->New(); |
|||
in := client->Get("http://rosettacode.org/mw/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=5000&format=xml"); |
|||
each(i : in) { |
|||
langs_xml += in->Get(i)->As(String); |
|||
}; |
|||
langs := StringSet->New(); |
|||
parser := XmlParser->New(langs_xml); |
|||
if(parser->Parse()) { |
|||
# get first item |
|||
results := parser->FindElements("/api/query/categorymembers/cm"); |
|||
each(i : results) { |
|||
element := results->Get(i)->As(XmlElement); |
|||
name := element->GetAttribute("title")->GetValue(); |
|||
offset := name->Find(':'); |
|||
if(offset > -1) { |
|||
lang := name->SubString(offset + 1, name->Size() - offset - 1); |
|||
langs->Insert(lang->ReplaceAll(" ", " ")); |
|||
}; |
|||
}; |
|||
}; |
|||
langs_counts := IntMap->New(); |
|||
client := HttpClient->New(); |
|||
html := client->Get("http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000"); |
|||
each(i : html) { |
|||
lines := html->Get(i)->As(String); |
|||
html_elements := lines->Split("\n"); |
|||
each(j : html_elements) { |
|||
element := html_elements[j]; |
|||
name : String; count : String; |
|||
regex := RegEx->New("<li><a href=\"(\\w|\\s|/|\\?|\\&|;|:|#)+\"\\stitle=\"Category:(\\w|\\s|#)+\">"); |
|||
found := regex->FindFirst(element); |
|||
if(found <> Nil) { |
|||
group1 := found->Size(); |
|||
regex := RegEx->New("(\\w|\\s)+"); |
|||
found := regex->Match(element, group1); |
|||
if(found <> Nil & found->Size() > 0) { |
|||
name := found; |
|||
# skip over some junk characters |
|||
group2 := group1 + found->Size() + 10; |
|||
regex := RegEx->New("\\s\\("); |
|||
found := regex->Match(element, group2); |
|||
if(found <> Nil) { |
|||
group3 := group2 + found->Size(); |
|||
regex := RegEx->New("\\d+"); |
|||
found := regex->Match(element, group3); |
|||
if(found <> Nil & found->Size() > 0) { |
|||
count := found; |
|||
}; |
|||
}; |
|||
}; |
|||
}; |
|||
if(name <> Nil & count <> Nil) { |
|||
if(langs->Has(name)) { |
|||
langs_counts->Insert(count->ToInt(), name); |
|||
}; |
|||
name := Nil; count := Nil; |
|||
}; |
|||
}; |
|||
}; |
|||
keys := langs_counts->GetKeys(); |
|||
count := 1; |
|||
for(i := keys->Size() - 1; i >= 0; i -=1;) { |
|||
key := keys->Get(i); |
|||
IO.Console->Print(count)->Print(". ")->Print(key)->Print(" - ")->PrintLine(langs_counts->Find(key)->As(String)); |
|||
count += 1; |
|||
}; |
|||
} |
|||
}</syntaxhighlight> |
|||
<pre>1. 849 - Tcl |
|||
2. 826 - Racket |
|||
3. 821 - Python |
|||
4. 759 - J |
|||
5. 757 - Ruby |
|||
6. 751 - Perl 6 |
|||
7. 743 - C |
|||
8. 736 - D |
|||
9. 728 - Go |
|||
10. 696 - Perl |
|||
...</pre> |
|||
=={{header|ooRexx}}== |
|||
{{trans|REXX}} |
|||
<syntaxhighlight lang="oorexx">/* REXX --------------------------------------------------------------- |
|||
* Create a list of Rosetta Code languages showing the number of tasks |
|||
* This program's logic is basically that of the REXX program |
|||
* rearranged to my taste and utilizing the array class of ooRexx |
|||
* which offers a neat way of sorting as desired, see :CLASS mycmp below |
|||
* For the input to this program open these links: |
|||
* http://rosettacode.org/wiki/Category:Programming_Languages |
|||
* http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000 |
|||
* and save the pages as LAN.txt and CAT.txt, respectively |
|||
* Output: RC_POP.txt list of languages sorted by popularity |
|||
* If test=1, additionally: |
|||
* RC_LNG.txt list of languages alphabetically sorted |
|||
* RC_TRN.txt list language name translations (debug) |
|||
*--------------------------------------------------------------------*/ |
|||
test=1 |
|||
name.='??' |
|||
l.=0 |
|||
safe='' |
|||
x00='00'x |
|||
linfid='RC_LAN.txt' |
|||
linfid='LAN.txt' /* language file */ |
|||
cinfid='CAT.txt' /* category file */ |
|||
oid='RC_POP.txt'; 'erase' oid |
|||
If test Then Do |
|||
tid='RC.TRN.txt'; 'erase' tid |
|||
tia='RC_LNG.txt'; 'erase' tia |
|||
End |
|||
Call init |
|||
call read_lang /* process language file */ |
|||
Call read_cat /* process category file */ |
|||
Call ot words(lang_list) 'possible languages' |
|||
Call ot words(lang_listr) 'relevant languages' |
|||
llrn=words(lang_listr) |
|||
If test Then |
|||
Call no_member |
|||
a=.array~new /* create array object */ |
|||
cnt.=0 |
|||
Do i=1 By 1 While lang_listr<>'' |
|||
Parse Var lang_listr ddu0 lang_listr |
|||
ddu=translate(ddu0,' ',x00) |
|||
a[i]=right(mem.ddu,3) name.ddu /* fill array element */ |
|||
z=mem.ddu /* number of members */ |
|||
cnt.z=cnt.z+1 /* number of such languages */ |
|||
End |
|||
n=i-1 /* number of output lines */ |
|||
a~sortWith(.mycmp~new) /* sort the array elements */ |
|||
/* see :CLASS mycmp below */ |
|||
/*--------------------------------------------------------------------- |
|||
* and now create the output |
|||
*--------------------------------------------------------------------*/ |
|||
Call o ' ' |
|||
Call o center('timestamp: ' date() time('Civil'),79,'-') |
|||
Call o ' ' |
|||
Call o right(lrecs,9) 'records read from file: ' linfid |
|||
Call o right(crecs,9) 'records read from file: ' cinfid |
|||
Call o right(llrn,9) 'relevant languages' |
|||
Call o ' ' |
|||
rank=0 |
|||
rank.=0 |
|||
Do i=1 To n |
|||
rank=rank+1 |
|||
Parse Value a[i] With o . 6 lang |
|||
ol=' rank: 'right(rank,3)' '||, |
|||
'('right(o,3) 'entries) 'lang |
|||
If cnt.o>1 Then Do |
|||
If rank.o=0 Then |
|||
rank.o=rank |
|||
ol=overlay(right(rank.o,3),ol,17) |
|||
ol=overlay('[tied]',ol,22) |
|||
End |
|||
Call o ol |
|||
End |
|||
Call o ' ' |
|||
Call o center('+ end of list +',72) |
|||
Say 'Output in' oid |
|||
If test Then Do |
|||
b=.array~new /* create array object */ |
|||
cnt.=0 |
|||
Do i=1 By 1 While lang_list<>'' |
|||
Parse Var lang_list ddu0 lang_list |
|||
ddu=translate(ddu0,' ',x00) |
|||
b[i]=right(mem.ddu,3) name.ddu /* fill array element */ |
|||
End |
|||
n=i-1 /* number of output lines */ |
|||
b~sortWith(.alpha~new) /* sort the array elements */ |
|||
Call oa n 'languages' |
|||
Do i=1 To n |
|||
Call oa b[i] |
|||
End |
|||
Say 'Sorted list of languages in' tia |
|||
End |
|||
Exit |
|||
o: |
|||
Return lineout(oid,arg(1)) |
|||
ot: |
|||
If test Then Call lineout tid,arg(1) |
|||
Return |
|||
oa: |
|||
If test Then Call lineout tia,arg(1) |
|||
Return |
|||
read_lang: |
|||
/*--------------------------------------------------------------------- |
|||
* Read the language page to determine the list of possible languages |
|||
* Output: l.lang>0 for all languages found |
|||
* name.lang original name of uppercased language name |
|||
* lang_list list of uppercased language names |
|||
* lrecs number of records read from language file |
|||
*--------------------------------------------------------------------*/ |
|||
l.=0 |
|||
name.='??' |
|||
lang_list='' |
|||
Do lrecs=0 While lines(linfid)\==0 |
|||
l=linein(linfid) /* read from language file */ |
|||
l=translate(l,' ','9'x) /* turn tabs to blanks */ |
|||
dd=space(l) /* remove extra blanks */ |
|||
ddu=translate(dd) |
|||
If pos('AUTOMATED ADMINISTRATION',ddu)>0 Then /* ignore this */ |
|||
Iterate |
|||
If pos('RETRIEVED FROM',ddu)\==0 Then /* this indicates the end */ |
|||
Leave |
|||
If dd=='' Then /* ignore all blank lines. */ |
|||
Iterate |
|||
If left(dd,1)\=='*' Then /* ignore lines w/o * */ |
|||
Iterate |
|||
ddo=fix_lang(dd) /* replace odd language names */ |
|||
If ddo<>dd Then Do /* show those that we found */ |
|||
Call ot ' ' dd |
|||
Call ot '>' ddo |
|||
dd=ddo |
|||
End |
|||
Parse Var dd '*' dd "<" /* extract the language name */ |
|||
ddu=strip(translate(dd)) /* translate to uppercase */ |
|||
If name.ddu='??' Then |
|||
name.ddu=dd /* remember 1st original name */ |
|||
l.ddu=l.ddu+1 |
|||
ddu_=translate(ddu,x00,' ') |
|||
If wordpos(ddu_,lang_list)=0 Then |
|||
lang_list=lang_list ddu_ |
|||
End |
|||
Return |
|||
read_cat: |
|||
/*--------------------------------------------------------------------- |
|||
* Read the category page to get language names and number of members |
|||
* Output: mem.ddu number of members for (uppercase) Language ddu |
|||
* lang_listr the list of relevant languages |
|||
*--------------------------------------------------------------------*/ |
|||
mem.=0 |
|||
lang_listr='' |
|||
Do crecs=0 While lines(cinfid)\==0 |
|||
l=get_cat(cinfid) /* read from category file */ |
|||
l=translate(l,' ','9'x) /* turn tabs to blanks */ |
|||
dd=space(l) /* remove extra blanks */ |
|||
If dd=='' Then /* ignore all blank lines. */ |
|||
Iterate |
|||
ddu=translate(dd) |
|||
ddo=fix_lang(dd) /* replace odd language names */ |
|||
If ddo<>dd Then Do /* show those that we found */ |
|||
Call ot ' ' dd |
|||
Call ot '>' ddo |
|||
dd=ddo |
|||
End |
|||
du=translate(dd) /* get an uppercase version. */ |
|||
If pos('RETRIEVED FROM',du)\==0 Then /* this indicates the end */ |
|||
Leave |
|||
Parse Var dd dd '<' "(" mems . /* extract the language name */ |
|||
/* and the number of members */ |
|||
dd=space(substr(dd,3)) |
|||
_=translate(dd) |
|||
If \l._ Then /* not a known language */ |
|||
Iterate /* ignore */ |
|||
if pos(',', mems)\==0 then |
|||
mems=changestr(",", mems, '') /* remove commas. */ |
|||
If\datatype(mems,'W') Then /* not a number of members */ |
|||
Iterate /* ignore */ |
|||
ddu=space(translate(dd)) |
|||
mem.ddu=mem.ddu+mems /* set o add number of members*/ |
|||
Call memory ddu /* list of relevant languages */ |
|||
End |
|||
Return |
|||
get_cat: |
|||
/*--------------------------------------------------------------------- |
|||
* get a (logical) line from the category file |
|||
* These two lines |
|||
* * Lotus 123 Macro Scripting |
|||
* </wiki/Category:Lotus_123_Macro_Scripting>�‎ (3 members) |
|||
* are returned as one line: |
|||
*-> * Lotus 123 Macro Scripting </wiki/Cate ... (3 members) |
|||
* we need language name and number of members in one line |
|||
*--------------------------------------------------------------------*/ |
|||
Parse Arg fid |
|||
If safe<>'' Then |
|||
ol=safe |
|||
Else Do |
|||
If lines(fid)=0 Then |
|||
Return '' |
|||
ol=linein(fid) |
|||
safe='' |
|||
End |
|||
If left(ol,3)=' *' Then Do |
|||
Do Until left(r,3)==' *' | lines(fid)=0 |
|||
r=linein(fid) |
|||
If left(r,3)==' *' Then Do |
|||
safe=r |
|||
Return ol |
|||
End |
|||
Else |
|||
ol=ol r |
|||
End |
|||
End |
|||
Return ol |
|||
memory: |
|||
ddu0=translate(ddu,x00,' ') |
|||
If wordpos(ddu0,lang_listr)=0 Then |
|||
lang_listr=lang_listr ddu0 |
|||
Return |
|||
fix_lang: Procedure Expose old. new. |
|||
Parse Arg s |
|||
Do k=1 While old.k\=='' /* translate Unicode variations. */ |
|||
If pos(old.k,s)\==0 Then |
|||
s=changestr(old.k,s,new.k) |
|||
End |
|||
Return s |
|||
init: |
|||
old.='' |
|||
old.1='UC++' /* '55432B2B'X */ |
|||
new.1="µC++" /* old UC++ --?ASCII-8: µC++ */ |
|||
old.2='МК-61/52' /* 'D09CD09A2D36312F3532'X */ |
|||
new.2='MK-61/52' /* somewhere a mistranslated: MK- */ |
|||
old.3='Déjà Vu' /* '44C3A96AC3A0205675'X */ |
|||
new.3='Déjà Vu' /* Unicode +¬j+á --?ASCII-8: Déjá */ |
|||
old.4='Caché' /* '43616368C3A9'X */ |
|||
new.4='Caché' /* Unicode ach+¬ --?ASCII-8: Caché */ |
|||
old.5='ÎœC++' /* 'CE9C432B2B'X */ |
|||
new.5="MC++" /* Unicode +£C++ --?ASCII-8: µC++ */ |
|||
/*-----------------------------------------------------------------*/ |
|||
Call ot 'Language replacements:' |
|||
Do ii=1 To 5 |
|||
Call ot ' ' left(old.ii,10) left(c2x(old.ii),20) '->' new.ii |
|||
End |
|||
Call ot ' ' |
|||
Return |
|||
no_member: Procedure Expose lang_list lang_listr tid x00 test |
|||
/*--------------------------------------------------------------------- |
|||
* show languages found in language file that are not referred to |
|||
* in the category file |
|||
*--------------------------------------------------------------------*/ |
|||
ll =wordsort(lang_list ) /* languages in language file */ |
|||
llr=wordsort(lang_listr) /* languages in category file */ |
|||
Parse Var ll l1 ll |
|||
Parse Var llr l2 llr |
|||
nn.=0 |
|||
Do Forever |
|||
Select |
|||
When l1=l2 Then Do |
|||
If l1='' Then /* both lists empty */ |
|||
Leave |
|||
Parse Var ll l1 ll /* get the next language */ |
|||
Parse Var llr l2 llr /* -"- */ |
|||
End |
|||
When l1<l2 Then Do /* in language file */ |
|||
/* and not in category file */ |
|||
z=nn.0+1 |
|||
nn.z=' 'translate(l1,' ',x00) /* show in test output */ |
|||
nn.0=z |
|||
Parse Var ll l1 ll /* next from language file */ |
|||
End |
|||
Otherwise Do |
|||
Call ot '?? 'translate(l2,' ',x00) /* show in test output */ |
|||
Say 'In category file but not in language file:' |
|||
Say '?? 'translate(l2,' ',x00) |
|||
Say 'Hit enter to proceed' |
|||
Pull . |
|||
Parse Var llr l2 llr /* next from category file */ |
|||
End |
|||
End |
|||
End |
|||
Call ot nn.0 'Languages without members:' /* heading */ |
|||
Do ii=1 To nn.0 |
|||
Call ot nn.ii |
|||
End |
|||
Return |
|||
::CLASS mycmp MIXINCLASS Comparator |
|||
::METHOD compare |
|||
/********************************************************************** |
|||
* smaller number is considered higher |
|||
* numbers equal: higher language considered higher |
|||
* otherwise return lower |
|||
**********************************************************************/ |
|||
Parse Upper Arg a,b |
|||
Parse Var a na +4 ta |
|||
Parse Var b nb +4 tb |
|||
Select |
|||
When na<<nb THEN res=1 |
|||
When na==nb Then Do |
|||
If ta<<tb Then res=-1 |
|||
Else res=1 |
|||
End |
|||
Otherwise res=-1 |
|||
End |
|||
Return res |
|||
::CLASS alpha MIXINCLASS Comparator |
|||
::METHOD compare |
|||
/********************************************************************** |
|||
* higher language considered higher |
|||
* otherwise return lower |
|||
**********************************************************************/ |
|||
Parse Upper Arg a,b |
|||
Parse Var a na +4 ta |
|||
Parse Var b nb +4 tb |
|||
If ta<<tb Then res=-1 |
|||
Else res=1 |
|||
Return res</syntaxhighlight> |
|||
Output (the beginning): |
|||
<pre> |
|||
------------------------timestamp: 24 Nov 2013 9:48am------------------------- |
|||
706 records read from file: LAN.txt |
|||
2204 records read from file: CAT.txt |
|||
502 relevant languages |
|||
rank: 1 (760 entries) Tcl |
|||
rank: 2 (724 entries) Racket |
|||
rank: 3 (708 entries) Python |
|||
rank: 4 (681 entries) C |
|||
</pre> |
|||
Note: If MC++ and µC++ are the same, they should/could be added together to get 501 languages. |
|||
=={{header|PascalABC.NET}}== |
|||
Using web scraping. May 2024. |
|||
<syntaxhighlight lang="delphi"> |
|||
uses System.Net; |
|||
begin |
|||
ServicePointManager.SecurityProtocol := SecurityProtocolType(3072); |
|||
var wc := new WebClient; |
|||
wc.Encoding := Encoding.UTF8; |
|||
var s := wc.DownloadString('https://rosettacode.org/wiki/Special:Categories?limit=5000'); |
|||
s.Matches('([^><]+)</a>.+\(([\d,]+) member') |
|||
.Select(x -> KV(x.Groups[1].Value,x.Groups[2].Value.Replace(',','').ToInteger)) |
|||
.Where(x -> not x.Key.StartsWith('Pages')) |
|||
.OrderByDescending(pair -> pair.Value).Numerate.Take(10) |
|||
.PrintLines(x -> $'Rank: {x[0],3} ({x[1].Value} entries) {x[1].Key}') |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Rank: 1 (1682 entries) Phix |
|||
Rank: 2 (1675 entries) Wren |
|||
Rank: 3 (1652 entries) Julia |
|||
Rank: 4 (1622 entries) Raku |
|||
Rank: 5 (1577 entries) Nim |
|||
Rank: 6 (1552 entries) Go |
|||
Rank: 7 (1548 entries) Perl |
|||
Rank: 8 (1531 entries) Python |
|||
Rank: 9 (1416 entries) J |
|||
Rank: 10 (1343 entries) Java |
|||
</pre> |
|||
=={{header|Oz}}== |
|||
{{libheader|OzHttpClient}} |
|||
Using web scraping. Does not filter non-language categories. |
|||
<syntaxhighlight lang="oz">declare |
|||
[HTTPClient] = {Module.link ['x-ozlib://mesaros/net/HTTPClient.ozf']} |
|||
[Regex] = {Module.link ['x-oz://contrib/regex']} |
|||
fun {GetPage RawUrl} |
|||
Client = {New HTTPClient.urlGET init(inPrms(toFile:false toStrm:true) _)} |
|||
Url = {VirtualString.toString RawUrl} |
|||
OutParams |
|||
HttpResponseParams |
|||
in |
|||
{Client getService(Url ?OutParams ?HttpResponseParams)} |
|||
{Client closeAll(true)} |
|||
OutParams.sOut |
|||
end |
|||
fun {GetCategories Doc} |
|||
{Map {Regex.allMatches "<li><a[^>]+>([^<]+)</a> \\(([0-9]+) member" Doc} |
|||
fun {$ Match} |
|||
Category = {Regex.group 1 Match Doc} |
|||
Count = {String.toInt {ByteString.toString {Regex.group 2 Match Doc}}} |
|||
in |
|||
Category#Count |
|||
end |
|||
} |
|||
end |
|||
Url = "http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000" |
|||
{System.showInfo "Retrieving..."} |
|||
Doc = {GetPage Url} |
|||
{System.showInfo "Parsing..."} |
|||
Cs = {GetCategories Doc} |
|||
in |
|||
for |
|||
Cat#Count in {Sort Cs fun {$ _#C1 _#C2} C1 > C2 end} |
|||
I in 1..20 |
|||
do |
|||
{System.showInfo I#". "#Count#" - "#Cat} |
|||
end</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. 371 - Tcl |
|||
2. 369 - Programming Tasks |
|||
3. 338 - Python |
|||
4. 324 - Ruby |
|||
5. 306 - Haskell |
|||
... |
|||
17. 225 - Oz |
|||
18. 214 - C++ |
|||
19. 209 - JavaScript |
|||
20. 208 - ALGOL 68 |
|||
</pre> |
|||
=={{header|Perl}}== |
|||
===By using the API=== |
|||
<syntaxhighlight lang="perl">use 5.010; |
|||
use MediaWiki::API; |
|||
my $api = |
|||
MediaWiki::API->new( { api_url => 'http://rosettacode.org/w/api.php' } ); |
|||
my @languages; |
|||
my $gcmcontinue; |
|||
while (1) { |
|||
my $apih = $api->api( |
|||
{ |
|||
action => 'query', |
|||
generator => 'categorymembers', |
|||
gcmtitle => 'Category:Programming Languages', |
|||
gcmlimit => 250, |
|||
prop => 'categoryinfo', |
|||
gcmcontinue => $gcmcontinue |
|||
} |
|||
); |
|||
push @languages, values %{ $apih->{'query'}{'pages'} }; |
|||
last if not $gcmcontinue = $apih->{'continue'}{'gcmcontinue'}; |
|||
} |
|||
for (@languages) { |
|||
$_->{'title'} =~ s/Category://; |
|||
$_->{'categoryinfo'}{'size'} //= 0; |
|||
} |
|||
my @sorted_languages = |
|||
reverse sort { $a->{'categoryinfo'}{'size'} <=> $b->{'categoryinfo'}{'size'} } |
|||
@languages; |
|||
binmode STDOUT, ':encoding(utf8)'; |
|||
my $n = 1; |
|||
for (@sorted_languages) { |
|||
printf "%3d. %20s - %3d\n", $n++, $_->{'title'}, |
|||
$_->{'categoryinfo'}{'size'}; |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1. Phix - 1576 |
|||
2. Wren - 1569 |
|||
3. Julia - 1540 |
|||
4. Raku - 1520 |
|||
5. Go - 1500 |
|||
6. Perl - 1468 |
|||
7. Python - 1422 |
|||
8. Nim - 1403 |
|||
9. J - 1278 |
|||
10. C - 1213 |
|||
...</pre> |
|||
=={{header|Phix}}== |
|||
The distributed version also has an output_html option. |
|||
{{libheader|Phix/libcurl}} |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Rank_Languages.exw</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">output_users</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">limit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 0 to list all</span> |
|||
<span style="color: #000000;">languages</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"http://rosettacode.org/wiki/Category:Programming_Languages"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">categories</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000"</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">rosettacode_cache</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- see [[Rosetta_Code/Count_examples#Phix]]</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">correct_name</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">ri</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`"`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`"`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`'`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`'`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xE2\x80\x99"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"'"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC3\xB6"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"o"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%3A"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">":"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%E2%80%93"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%E2%80%99"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"'"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%27"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"'"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%2B"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%C3%A8"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"e"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%C3%A9"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"e"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%C3%B6"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"o"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%C5%91"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"o"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%22"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`"`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%2A"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"*"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC2\xB5"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"u"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC3\xA0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"a"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC3\xA6"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"a"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC3\xA9"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"e"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC3\xB4"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"o"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xC5\x8D"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"o"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xCE\x9C"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"u"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xD0\x9C\xD0\x9A"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"MK"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\xE0\xAE\x89\xE0\xAE\xAF\xE0\xAE\xBF\xE0\xAE\xB0\xE0\xAF\x8D/"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"APEX"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Apex"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"uC++ "</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"UC++"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`CASIO BASIC`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Casio BASIC`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Visual BASIC`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Visual Basic`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`INTERCAL`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Intercal`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`SETL4`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Setl4`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`QBASIC`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`QBasic`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`RED`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Red`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`OCTAVE`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`Octave`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`OoREXX`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`OoRexx`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">ri</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">/</span><span style="color: #000000;">sets</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">cat_title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">`title="Category:`</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">extract_names</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">results</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- {rank,count,name}</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">get_file_type</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"rc_cache"</span><span style="color: #0000FF;">)!=</span><span style="color: #004600;">FILETYPE_DIRECTORY</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">create_directory</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"rc_cache"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"cannot create rc_cache directory"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000080;font-style:italic;">-- 1) extract languages from eg title="Category:Phix"</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">language_names</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">langs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">open_download</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"languages.htm"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">languages</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">language_name</span> |
|||
<span style="color: #000000;">langs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">langs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">`<div class="printfooter">`</span><span style="color: #0000FF;">,</span><span style="color: #000000;">langs</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"<h2>Subcategories</h2>"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">langs</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">k</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cat_title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">langs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">start</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cat_title</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'"'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">langs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">language_name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">correct_name</span><span style="color: #0000FF;">(</span><span style="color: #000000;">langs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..</span><span style="color: #000000;">start</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000000;">language_names</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">language_names</span><span style="color: #0000FF;">,</span><span style="color: #000000;">language_name</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
<span style="color: #000080;font-style:italic;">-- 2) extract results from eg title="Category:Phix">Phix</a>?? (997 members)</li> |
|||
-- but obviously only when we have found that language in the phase above. |
|||
-- (note there is / ignore some wierd uncode-like stuff after the </a>...)</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">cats</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">open_download</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"categories.htm"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">categories</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cat_title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cats</span><span style="color: #0000FF;">,</span><span style="color: #000000;">start</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cat_title</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'"'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cats</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">language_name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">correct_name</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cats</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..</span><span style="color: #000000;">start</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"</a>"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cats</span><span style="color: #0000FF;">,</span><span style="color: #000000;">start</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">4</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">output_users</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">language_name</span><span style="color: #0000FF;">)></span><span style="color: #000000;">5</span> |
|||
<span style="color: #008080;">and</span> <span style="color: #000000;">language_name</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" User"</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">language_name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">correct_name</span><span style="color: #0000FF;">(</span><span style="color: #000000;">language_name</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">6</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #000000;">language_name</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">language_name</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">and</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">language_name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">language_names</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cats</span><span style="color: #0000FF;">[</span><span style="color: #000000;">start</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"(<"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> <span style="color: #000000;">start</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span> <span style="color: #000080;font-style:italic;">-- (ignore)</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">members</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cats</span><span style="color: #0000FF;">[</span><span style="color: #000000;">start</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'<'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cats</span><span style="color: #0000FF;">,</span><span style="color: #000000;">start</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)]</span> |
|||
<span style="color: #000000;">members</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">","</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"(%d member%s)<"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">results</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">results</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">language_name</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
<span style="color: #000000;">results</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort_columns</span><span style="color: #0000FF;">(</span><span style="color: #000000;">results</span><span style="color: #0000FF;">,{-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">})</span> <span style="color: #000080;font-style:italic;">-- (descending 2nd column, then asc 3rd) |
|||
--3) assign rank</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">rank</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">results</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">count</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">results</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prev</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">results</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"="</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #000000;">rank</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span> |
|||
<span style="color: #000000;">results</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rank</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">count</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">results</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">results</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">progress</span><span style="color: #0000FF;">(</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">limit</span><span style="color: #0000FF;">?</span><span style="color: #000000;">limit</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">results</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%3s: %,d - %s\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">results</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #000000;">extract_names</span><span style="color: #0000FF;">())</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
As of July 31st, 2019 |
|||
<pre> |
|||
Downloading rc_cache\languages.htm... |
|||
Downloading rc_cache\categories.htm... |
|||
1: 1,156 - Go |
|||
2: 1,092 - Phix |
|||
3: 1,090 - Perl 6 |
|||
4: 1,074 - Julia |
|||
5: 1,066 - Python |
|||
6: 1,046 - Kotlin |
|||
7: 1,026 - Perl |
|||
8: 991 - Racket |
|||
9: 953 - C |
|||
10: 945 - J |
|||
11: 943 - Zkl |
|||
12: 930 - Tcl |
|||
13: 915 - REXX |
|||
14: 910 - Java |
|||
15: 897 - Ruby |
|||
16: 892 - D |
|||
17: 872 - Haskell |
|||
18: 816 - Sidef |
|||
19: 814 - Scala |
|||
20: 786 - C sharp |
|||
</pre> |
|||
=={{header|PicoLisp}}== |
|||
<syntaxhighlight lang="picolisp">(load "@lib/http.l") |
|||
(for (I . X) |
|||
(flip |
|||
(sort |
|||
(make |
|||
(client "rosettacode.org" 80 |
|||
"mw/index.php?title=Special:Categories&limit=5000" |
|||
(while (from "<li><a href=\"/wiki/Category:") |
|||
(let Cat (till "\"") |
|||
(from "(") |
|||
(when (format (till " " T)) |
|||
(link (cons @ (ht:Pack Cat))) ) ) ) ) ) ) ) |
|||
(prinl (align 3 I) ". " (car X) " - " (cdr X)) )</syntaxhighlight> |
|||
{{out|Output (dec15)}} |
|||
<pre> 1. 903 - Racket |
|||
2. 897 - Tcl |
|||
3. 863 - Python |
|||
4. 821 - J |
|||
5. 796 - Perl_6 |
|||
6. 780 - Programming_Tasks |
|||
7. 778 - Ruby |
|||
8. 767 - C |
|||
9. 751 - Go |
|||
10. 745 - D |
|||
...</pre> |
|||
=={{header|PowerShell}}== |
|||
{{trans|C#}} |
|||
<syntaxhighlight lang="powershell"> |
|||
$get1 = (New-Object Net.WebClient).DownloadString("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=700&format=json") |
|||
$get2 = (New-Object Net.WebClient).DownloadString("http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000") |
|||
$match1 = [regex]::matches($get1, "`"title`":`"Category:(.+?)`"") |
|||
$match2 = [regex]::matches($get2, "title=`"Category:([^`"]+?)`">[^<]+?</a>[^\(]*\((\d+) members\)") |
|||
$r = 1 |
|||
$langs = $match1 | foreach { $_.Groups[1].Value.Replace("\","") } |
|||
$res = $match2 | sort -Descending {[Int]$($_.Groups[2].Value)} | foreach { |
|||
if ($langs.Contains($_.Groups[1].Value)) |
|||
{ |
|||
[pscustomobject]@{ |
|||
Rank = "$r" |
|||
Members = "$($_.Groups[2].Value)" |
|||
Language = "$($_.Groups[1].Value)" |
|||
} |
|||
$r++ |
|||
} |
|||
} |
|||
1..30 | foreach{ |
|||
[pscustomobject]@{ |
|||
"Rank 1..30" = "$($_)" |
|||
"Members 1..30" = "$($res[$_-1].Members)" |
|||
"Language 1..30" = "$($res[$_-1].Language)" |
|||
"Rank 31..60" = "$($_+30)" |
|||
"Members 31..60" = "$($res[$_+30].Members)" |
|||
"Language 31..60" = "$($res[$_+30].Language)" |
|||
} |
|||
}| Format-Table -AutoSize |
|||
</syntaxhighlight> |
|||
<b>Output: August 04, 2015</b> |
|||
<pre> |
|||
Rank 1..30 Members 1..30 Language 1..30 Rank 31..60 Members 31..60 Language 31..60 |
|||
---------- ------------- -------------- ----------- -------------- --------------- |
|||
1 887 Tcl 31 405 Seed7 |
|||
2 877 Racket 32 397 Julia |
|||
3 853 Python 33 389 PL/I |
|||
4 798 J 34 387 Fortran |
|||
5 775 Ruby 35 386 ALGOL 68 |
|||
6 766 Perl 6 36 376 Lua |
|||
7 758 C 37 369 Pascal |
|||
8 746 Go 38 367 R |
|||
9 740 D 39 364 Groovy |
|||
10 710 Perl 40 363 F Sharp |
|||
11 701 REXX 41 363 Forth |
|||
12 692 PicoLisp 42 358 PHP |
|||
13 682 Haskell 43 342 AWK |
|||
14 675 Mathematica 44 340 Sidef |
|||
15 652 Java 45 335 MATLAB |
|||
16 623 Ada 46 325 Liberty BASIC |
|||
17 591 AutoHotkey 47 297 Octave |
|||
18 562 C++ 48 287 Factor |
|||
19 551 Common Lisp 49 286 Scheme |
|||
20 548 Scala 50 285 NetRexx |
|||
21 532 BBC BASIC 51 284 Oforth |
|||
22 523 Icon 52 280 Oz |
|||
23 516 C sharp 53 274 Run BASIC |
|||
24 508 OCaml 54 272 E |
|||
25 502 Nim 55 271 Bracmat |
|||
26 488 PureBasic 56 268 PowerShell |
|||
27 487 Clojure 57 263 Prolog |
|||
28 455 Erlang 58 260 Lasso |
|||
29 441 PARI/GP 59 249 Delphi |
|||
30 434 JavaScript 60 239 Smalltalk |
|||
</pre> |
|||
===PowerShell: Using web scraping=== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="powershell"> |
|||
$response = (New-Object Net.WebClient).DownloadString("http://rosettacode.org/wiki/Category:Programming_Languages") |
|||
$languages = [regex]::matches($response,'title="Category:(.*?)">') | foreach {$_.Groups[1].Value} |
|||
$response = [Net.WebClient]::new().DownloadString("http://rosettacode.org/w/index.php?title=Special:Categories&limit=5000") |
|||
$response = [regex]::Replace($response,'(\d+),(\d+)','$1$2') |
|||
$members = [regex]::matches($response,'<li><a[^>]+>([^<]+)</a>[^(]*[(](\d+) member[s]?[)]</li>') | foreach { [pscustomobject]@{ |
|||
Members = [Int]($_.Groups[2].Value) |
|||
Language = [String]($_.Groups[1].Value) |
|||
}} | where {$languages.Contains($_.Language)} | sort -Descending Members |
|||
Get-Date -UFormat "Sample output on %d %B %Y at %R %Z" |
|||
$members | Select-Object -First 10 | foreach -Begin {$r, $rank, $count = 0, 0,-1} { |
|||
$r++ |
|||
if ($count -ne $_.Members) {$rank = $r} |
|||
$count = $_.Members |
|||
$x = $_.Members.ToString("N0",[System.Globalization.CultureInfo]::CreateSpecificCulture('en-US')) |
|||
$entry = "($x entries)" |
|||
[String]::Format("Rank: {0,2} {1,15} {2}",$rank,$entry,$_.Language) |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Sample output on 13 septembre 2019 at 12:17 +02 |
|||
Rank: 1 (1,177 entries) Go |
|||
Rank: 2 (1,116 entries) Phix |
|||
Rank: 3 (1,107 entries) Perl 6 |
|||
Rank: 4 (1,104 entries) Julia |
|||
Rank: 5 (1,080 entries) Python |
|||
Rank: 6 (1,053 entries) Kotlin |
|||
Rank: 7 (1,048 entries) Perl |
|||
Rank: 8 (1,045 entries) Racket |
|||
Rank: 9 (970 entries) C |
|||
Rank: 10 (960 entries) Zkl |
|||
</pre> |
|||
===PowerShell: Using MediaWiki API method=== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="powershell"> |
|||
$languages = @{} |
|||
$Body = @{ |
|||
format = 'json' |
|||
action = 'query' |
|||
generator = 'categorymembers' |
|||
gcmtitle = 'Category:Programming Languages' |
|||
gcmlimit = '200' |
|||
gcmcontinue = '' |
|||
continue = '' |
|||
prop = 'categoryinfo' |
|||
} |
|||
$params = @{ |
|||
Method = 'Get' |
|||
Uri = 'http://rosettacode.org/mw/api.php' |
|||
Body = $Body |
|||
} |
|||
while ($true) { |
|||
$response = Invoke-RestMethod @params |
|||
$response.query.pages.PSObject.Properties | ForEach-Object { |
|||
if (($_.value.PSObject.Properties.Name -Contains 'title') -and ($_.value.PSObject.Properties.Name -Contains 'categoryinfo')) { |
|||
$languages[$_.value.title.replace('Category:', '')] = $_.value.categoryinfo.size |
|||
} |
|||
} |
|||
if ($response.PSObject.Properties.Name -Contains 'continue') { |
|||
$gcmcontinue = $response.continue.gcmcontinue |
|||
$params.Body.gcmcontinue = $gcmcontinue |
|||
} else { |
|||
break |
|||
} |
|||
} |
|||
$members = $languages.GetEnumerator() | sort -Descending value |
|||
Get-Date -UFormat "Sample output on %d %B %Y at %R %Z" |
|||
$members | Select-Object -First 10 | foreach -Begin {$r, $rank, $count = 0, 0,-1} { |
|||
$r++ |
|||
if ($count -ne $_.Members) {$rank = $r} |
|||
$count = $_.Value |
|||
$x = $_.Value.ToString("N0",[System.Globalization.CultureInfo]::CreateSpecificCulture('en-US')) |
|||
$entry = "($x entries)" |
|||
[String]::Format("Rank: {0,2} {1,15} {2}",$rank, $entry, $_.Name) |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Sample output on 05 juillet 2022 at 19:53 +02 |
|||
Rank: 1 (1,552 entries) Phix |
|||
Rank: 2 (1,545 entries) Wren |
|||
Rank: 3 (1,521 entries) Julia |
|||
Rank: 4 (1,498 entries) Go |
|||
Rank: 5 (1,497 entries) Raku |
|||
Rank: 6 (1,456 entries) Perl |
|||
Rank: 7 (1,402 entries) Nim |
|||
Rank: 8 (1,401 entries) Python |
|||
Rank: 9 (1,206 entries) C |
|||
Rank: 10 (1,180 entries) J |
|||
</pre> |
|||
=={{header|PureBasic}}== |
|||
===Using MediaWiki API method=== |
|||
<syntaxhighlight lang="purebasic">Procedure handleError(value, msg.s) |
|||
If value = 0 |
|||
MessageRequester("Error", msg) |
|||
End |
|||
EndIf |
|||
EndProcedure |
|||
Structure languageInfo |
|||
name.s |
|||
pageCount.i |
|||
EndStructure |
|||
#JSON_web_data = 0 ;ID# for our parsed JSON web data object |
|||
Define NewList languages.languageInfo() |
|||
Define blah.s, object_val, allPages_mem, title_mem, page_mem, categoryInfo_mem, continue_mem |
|||
Define url$, title$, currentPage$, language$, langPageCount, gcmcontinue$, *bufferPtr |
|||
handleError(InitNetwork(), "Unable to initialize network functions.") |
|||
Repeat |
|||
url$ = "http://www.rosettacode.org/mw/api.php?action=query" + |
|||
"&generator=categorymembers&gcmtitle=Category:Programming%20Languages" + |
|||
"&gcmlimit=500" + "&gcmcontinue=" + gcmcontinue$ + |
|||
"&prop=categoryinfo&format=json" |
|||
*bufferPtr = ReceiveHTTPMemory(url$) |
|||
handleError(*bufferPtr, "Unable to receive web page data.") |
|||
If CatchJSON(#JSON_web_data, *bufferPtr, MemorySize(*bufferPtr)) = 0 |
|||
MessageRequester("Error", JSONErrorMessage() + " at position " + |
|||
JSONErrorPosition() + " in line " + |
|||
JSONErrorLine() + " of JSON web Data") |
|||
End |
|||
EndIf |
|||
FreeMemory(*bufferPtr) |
|||
object_val = JSONValue(#JSON_web_data) |
|||
allPages_mem = GetJSONMember(GetJSONMember(object_val, "query"), "pages") |
|||
If ExamineJSONMembers(allPages_mem) |
|||
While NextJSONMember(allPages_mem) |
|||
page_mem = JSONMemberValue(allPages_mem) |
|||
title_mem = GetJSONMember(page_mem, "title") |
|||
If title_mem |
|||
title$ = GetJSONString(title_mem) |
|||
If Left(title$, 9) = "Category:" |
|||
language$ = Mid(title$, 10) |
|||
categoryInfo_mem = GetJSONMember(page_mem, "categoryinfo") |
|||
If categoryInfo_mem |
|||
langPageCount = GetJSONInteger(GetJSONMember(categoryInfo_mem, "pages")) |
|||
Else |
|||
langPageCount = 0 |
|||
EndIf |
|||
AddElement(languages()) |
|||
languages()\name = language$ |
|||
languages()\pageCount = langPageCount |
|||
EndIf |
|||
EndIf |
|||
Wend |
|||
EndIf |
|||
;check for continue |
|||
continue_mem = GetJSONMember(object_val, "continue") |
|||
If continue_mem |
|||
gcmcontinue$ = GetJSONString(GetJSONMember(continue_mem, "gcmcontinue")) |
|||
Else |
|||
gcmcontinue$ = "" |
|||
EndIf |
|||
FreeJSON(#JSON_web_data) |
|||
Until gcmcontinue$ = "" |
|||
;all data has been aquired, now process and display it |
|||
SortStructuredList(languages(), #PB_Sort_Descending, OffsetOf(languageInfo\pageCount), #PB_Integer) |
|||
If OpenConsole() |
|||
If ListSize(languages()) |
|||
Define i, *startOfGroupPtr.languageInfo, *lastElementPtr, groupSize, rank |
|||
Define outputSize = 100, outputLine |
|||
PrintN(Str(ListSize(languages())) + " languages." + #CRLF$) |
|||
LastElement(languages()) |
|||
*lastElementPtr = @languages() ;pointer to last element |
|||
FirstElement(languages()) |
|||
*startOfGroupPtr = @languages() ;pointer to first element |
|||
groupSize = 1 |
|||
rank = 1 |
|||
While NextElement(languages()) |
|||
If languages()\pageCount <> *startOfGroupPtr\pageCount Or *lastElementPtr = @languages() |
|||
;display a group of languages at the same rank |
|||
ChangeCurrentElement(languages(), *startOfGroupPtr) |
|||
For i = 1 To groupSize |
|||
;display output in groups to allow viewing of all entries |
|||
If outputLine = 0 |
|||
PrintN(" Rank Tasks Language") |
|||
PrintN(" ------ ----- --------") |
|||
EndIf |
|||
PrintN(RSet(Str(rank), 6) + ". " + |
|||
RSet(Str(languages()\pageCount), 4) + " " + |
|||
languages()\name) |
|||
outputLine + 1 |
|||
If outputLine >= outputSize |
|||
Print(#CRLF$ + #CRLF$ + "Press ENTER to continue" + #CRLF$): Input() |
|||
outputLine = 0 |
|||
EndIf |
|||
NextElement(languages()) |
|||
Next |
|||
rank + groupSize |
|||
groupSize = 1 |
|||
*startOfGroupPtr = @languages() |
|||
Else |
|||
groupSize + 1 |
|||
EndIf |
|||
Wend |
|||
Else |
|||
PrintN("No language categories found.") |
|||
EndIf |
|||
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input() |
|||
CloseConsole() |
|||
EndIf</syntaxhighlight> |
|||
Sample output: |
|||
<pre>608 languages. |
|||
Rank Tasks Language |
|||
------ ----- -------- |
|||
1. 904 Racket |
|||
2. 894 Tcl |
|||
3. 852 Python |
|||
4. 836 J |
|||
5. 803 Perl 6 |
|||
6. 787 Ruby |
|||
7. 772 C |
|||
8. 752 Go |
|||
9. 743 D |
|||
10. 728 Perl |
|||
11. 726 REXX |
|||
12. 702 Haskell |
|||
13. 697 Java |
|||
14. 696 PicoLisp |
|||
15. 693 Zkl |
|||
16. 687 Mathematica |
|||
17. 625 Ada |
|||
18. 603 C++ |
|||
18. 603 Sidef |
|||
18. 603 AutoHotkey |
|||
21. 578 Unicon |
|||
22. 574 Common Lisp |
|||
23. 558 Scala |
|||
24. 530 BBC BASIC |
|||
25. 527 C sharp |
|||
26. 520 Icon |
|||
27. 507 OCaml |
|||
28. 503 Nim |
|||
29. 497 PureBasic |
|||
..... |
|||
514. 0 Rubylog |
|||
514. 0 Refal |
|||
514. 0 QuakeC |
|||
514. 0 Mirelle |
|||
514. 0 .QL |
|||
514. 0 M680x0 |
|||
514. 0 Datalog |
|||
514. 0 Cilk++ |
|||
514. 0 Cecil |
|||
514. 0 AspectC++ |
|||
514. 0 8080 Assembly |
|||
514. 0 OpenC++ |
|||
514. 0 AMPL |
|||
514. 0 UserRPL |
|||
514. 0 TeLa |
|||
514. 0 UScript |
|||
514. 0 TAL |
|||
514. 0 Zonnon |
|||
514. 0 Superbase BASIC |
|||
514. 0 VAX Assembly |
|||
514. 0 Star |
|||
514. 0 VRML |
|||
514. 0 WML |
|||
514. 0 X10 |
|||
514. 0 XS |
|||
514. 0 XBase |
|||
514. 0 UC++ |
|||
514. 0 True BASIC |
|||
514. 0 Thistle |
|||
</pre> |
|||
===Using web scraping method=== |
|||
<syntaxhighlight lang="purebasic"> |
|||
;Uses a web scraping method. |
|||
;It is limited to only retrieving 5000 language categories and the counts contain |
|||
;some slight inaccuracies. |
|||
Structure Language |
|||
count.i |
|||
Name.s |
|||
EndStructure |
|||
Dim Row.Language(5000) |
|||
Procedure handleError(value, msg.s) |
|||
If value = 0 |
|||
MessageRequester("Error", msg) |
|||
End |
|||
EndIf |
|||
EndProcedure |
|||
handleError(InitNetwork(), "Unable to initialize network functions.") |
|||
; Lines have been split to fit RC's 80 char preferences |
|||
ignore$ = "Basic language learning Encyclopedia Implementations " + |
|||
"Language Implementations Language users " + |
|||
"Maintenance/OmitCategoriesCreated Programming Languages " + |
|||
"Programming Tasks RCTemplates Solutions by Library Solutions by " + |
|||
"Programming Language Solutions by Programming Task Unimplemented " + |
|||
"tasks by language WikiStubs Examples needing attention " + |
|||
"Impl needed" |
|||
url$ = "http://www.rosettacode.org/mw/index.php?" + |
|||
"title=Special:Categories&limit=5000" |
|||
ReceiveHTTPFile(url$, "special.htm") |
|||
ReadFile(0, "special.htm", #PB_UTF8) |
|||
While Not Eof(0) |
|||
i + 1 |
|||
x1$ = ReadString(0) |
|||
x2$ = Mid(x1$, FindString(x1$, "member", 1) - 4 , 3) |
|||
Row(i)\count = Val(Trim(RemoveString(x2$, "("))) |
|||
x3$ = Mid(x1$, FindString(x1$, Chr(34) + ">", 1) + 2, 30) |
|||
Row(i)\Name = Left(x3$, FindString(x3$, "<", 1) - 1) |
|||
If FindString(ignore$, Row(i)\Name, 1) Or Row(i)\Name = "" |
|||
Row(i)\count = 0 |
|||
EndIf |
|||
Wend |
|||
offset=OffsetOf(Language\count) |
|||
SortStructuredArray(Row(), #PB_Sort_Descending, offset, #PB_Integer) |
|||
OpenConsole() |
|||
For i = 0 To 29 |
|||
PrintN( Str(i + 1) + ". " + Str(Row(i)\count) + " - " + Row(i)\Name) |
|||
Next |
|||
Input()</syntaxhighlight> |
|||
Sample output: |
|||
<pre>1. 907 - Racket |
|||
2. 898 - Tcl |
|||
3. 868 - Python |
|||
4. 839 - J |
|||
5. 807 - Perl 6 |
|||
6. 790 - Ruby |
|||
7. 756 - Go |
|||
8. 746 - D |
|||
9. 732 - Perl |
|||
10. 729 - REXX |
|||
11. 705 - Haskell |
|||
12. 700 - Java |
|||
13. 699 - PicoLisp |
|||
14. 694 - Zkl |
|||
15. 690 - Mathematica |
|||
16. 629 - Ada |
|||
17. 606 - C++ |
|||
18. 606 - AutoHotkey |
|||
19. 604 - Sidef |
|||
20. 581 - Unicon |
|||
21. 577 - Common Lisp |
|||
22. 561 - Scala |
|||
23. 533 - BBC BASIC |
|||
24. 530 - C sharp |
|||
25. 523 - Icon |
|||
26. 510 - OCaml |
|||
27. 504 - Nim |
|||
28. 500 - PureBasic |
|||
29. 494 - Clojure |
|||
30. 491 - JavaScript</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
===Python: Using web scraping=== |
|||
Works with: Python 2.6 |
|||
Using <code>requests</code> library. |
|||
< |
<syntaxhighlight lang="python">import requests |
||
import re |
import re |
||
response = requests.get("http://rosettacode.org/wiki/Category:Programming_Languages").text |
|||
def key1(x): |
|||
languages = re.findall('title="Category:(.*?)">',response)[:-3] # strip last 3 |
|||
return int(x.split()[0]) |
|||
response = requests.get("http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000").text |
|||
response = re.sub('(\d+),(\d+)',r'\1'+r'\2',response) # strip ',' from popular languages above 999 members |
|||
members = re.findall('<li><a[^>]+>([^<]+)</a>[^(]*[(](\\d+) member[s]*[)]</li>',response) # find language and members |
|||
for cnt, (language, members) in enumerate(sorted(members, key=lambda x: -int(x[1]))[:15]): # show only top 15 languages |
|||
entries = [] |
|||
if language in languages: |
|||
print("{:4d} {:4d} - {}".format(cnt+1, int(members), language)) |
|||
</syntaxhighlight> |
|||
for line in a: |
|||
{{out|Output (as of Dec 21, 2020)}} |
|||
match = re.search('>([^<>]*)</a> \((\d+) members?\)', line) |
|||
1 1306 - Go |
|||
if match: entries.append(match.group(2) + ' - ' + match.group(1)) |
|||
2 1275 - Phix |
|||
3 1265 - Julia |
|||
4 1257 - Raku |
|||
5 1196 - Python |
|||
6 1182 - Perl |
|||
7 1107 - Kotlin |
|||
8 1080 - C |
|||
9 1074 - Java |
|||
10 1061 - Racket |
|||
11 1022 - REXX |
|||
12 1012 - Zkl |
|||
13 1002 - J |
|||
14 983 - Ruby |
|||
15 972 - Haskell |
|||
===Python: Using MediaWiki API method=== |
|||
a.close() |
|||
<syntaxhighlight lang="python"> |
|||
import requests |
|||
import operator |
|||
import re |
|||
api_url = 'http://rosettacode.org/mw/api.php' |
|||
for c, line in enumerate(sorted(entries, key=key1, reverse=True),start=1): |
|||
languages = {} |
|||
print "%3d. %s" % (c, line)</lang> |
|||
parameters = { |
|||
'format': 'json', |
|||
'action': 'query', |
|||
'generator': 'categorymembers', |
|||
'gcmtitle': 'Category:Programming Languages', |
|||
'gcmlimit': '200', |
|||
'gcmcontinue': '', |
|||
'continue': '', |
|||
'prop': 'categoryinfo' |
|||
} |
|||
while(True): |
|||
response = requests.get(api_url, params=parameters).json() |
|||
for k,v in response['query']['pages'].items(): |
|||
if 'title' in v and 'categoryinfo' in v: |
|||
languages[v['title']]=v['categoryinfo']['size'] |
|||
if 'continue' in response: |
|||
gcmcontinue = response['continue']['gcmcontinue'] |
|||
# print(gcmcontinue) |
|||
parameters.update({'gcmcontinue': gcmcontinue}) |
|||
else: |
|||
break |
|||
# report top 15 languages |
|||
for i, (language, size) in enumerate(sorted(languages.items(), key=operator.itemgetter(1), reverse=True)[:15]): |
|||
print("{:4d} {:4d} - {}".format(i+1, size, re.sub('Category:','',language))) # strip Category: from language |
|||
</syntaxhighlight> |
|||
{{out|Output (as of Dec 21, 2020)}} |
|||
1 1306 - Go |
|||
2 1275 - Phix |
|||
3 1265 - Julia |
|||
4 1257 - Raku |
|||
5 1196 - Python |
|||
6 1182 - Perl |
|||
7 1107 - Kotlin |
|||
8 1080 - C |
|||
9 1074 - Java |
|||
10 1061 - Racket |
|||
11 1022 - REXX |
|||
12 1012 - Zkl |
|||
13 1002 - J |
|||
14 983 - Ruby |
|||
15 972 - Haskell |
|||
=={{header|R}}== |
|||
<syntaxhighlight lang="rsplus"> |
|||
library(rvest) |
|||
library(dplyr) |
|||
options(stringsAsFactors=FALSE) |
|||
# getting the required table from the rosetta website |
|||
langUrl <- "https://rosettacode.org/wiki/Rosetta_Code/Rank_languages_by_popularity/Full_list" |
|||
langs <- read_html(langUrl) %>% |
|||
html_nodes(xpath='/html/body/div/div/div[1]/div[3]/main/div[2]/div[3]/div[1]/table') %>% |
|||
html_table() %>% |
|||
data.frame() %>% |
|||
select(c("Rank","TaskEntries","Language")) |
|||
# changing the columns to required format |
|||
langs$Rank = paste("Rank: ",langs$Rank) |
|||
langs$TaskEntries = paste0("(", format(langs$TaskEntries, big.mark = ",") |
|||
," entries", ")") |
|||
names(langs) <- NULL |
|||
langs[1:10,] |
|||
</syntaxhighlight> |
|||
{{out|Output (as of October, 24, 2022)}} |
|||
<pre> |
|||
1 Rank: 1 (1,589 entries) Phix |
|||
2 Rank: 1 (1,589 entries) Wren |
|||
3 Rank: 3 (1,552 entries) Julia |
|||
4 Rank: 4 (1,535 entries) Raku |
|||
5 Rank: 5 (1,500 entries) Go |
|||
6 Rank: 6 (1,485 entries) Perl |
|||
7 Rank: 7 (1,422 entries) Python |
|||
8 Rank: 8 (1,402 entries) Nim |
|||
9 Rank: 9 (1,293 entries) J |
|||
10 Rank: 10 (1,213 entries) C |
|||
</pre> |
|||
=={{header|Racket}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="racket">#lang racket |
|||
(require racket/hash |
|||
net/url |
|||
json) |
|||
(define limit 15) |
|||
(define (replacer cat) (regexp-replace #rx"^Category:(.*?)$" cat "\\1")) |
|||
(define category "Category:Programming Languages") |
|||
(define entries "entries") |
|||
(define api-url (string->url "http://rosettacode.org/mw/api.php")) |
|||
(define (make-complete-url gcmcontinue) |
|||
(struct-copy url api-url |
|||
[query `([format . "json"] |
|||
[action . "query"] |
|||
[generator . "categorymembers"] |
|||
[gcmtitle . ,category] |
|||
[gcmlimit . "200"] |
|||
[gcmcontinue . ,gcmcontinue] |
|||
[continue . ""] |
|||
[prop . "categoryinfo"])])) |
|||
(define @ hash-ref) |
|||
(define table (make-hash)) |
|||
(let loop ([gcmcontinue ""]) |
|||
(define resp (read-json (get-pure-port (make-complete-url gcmcontinue)))) |
|||
(hash-union! table |
|||
(for/hash ([(k v) (in-hash (@ (@ resp 'query) 'pages))]) |
|||
(values (@ v 'title #f) (@ (@ v 'categoryinfo (hash)) 'size 0)))) |
|||
(cond [(@ resp 'continue #f) => (λ (c) (loop (@ c 'gcmcontinue)))])) |
|||
(for/fold ([prev #f] [rank #f] #:result (void)) |
|||
([item (in-list (sort (hash->list table) > #:key cdr))] [i (in-range limit)]) |
|||
(match-define (cons cat size) item) |
|||
(define this-rank (if (equal? prev size) rank (add1 i))) |
|||
(printf "Rank: ~a ~a ~a\n" |
|||
(~a this-rank #:align 'right #:min-width 2) |
|||
(~a (format "(~a ~a)" size entries) #:align 'right #:min-width 14) |
|||
(replacer cat)) |
|||
(values size this-rank))</syntaxhighlight> |
|||
Output on September 4, 2019: |
|||
<pre> |
|||
Rank: 1 (1176 entries) Go |
|||
Rank: 2 (1112 entries) Phix |
|||
Rank: 3 (1107 entries) Perl 6 |
|||
Rank: 4 (1099 entries) Julia |
|||
Rank: 5 (1079 entries) Python |
|||
Rank: 6 (1053 entries) Kotlin |
|||
Rank: 7 (1038 entries) Racket |
|||
Rank: 8 (1037 entries) Perl |
|||
Rank: 9 (968 entries) C |
|||
Rank: 10 (960 entries) Zkl |
|||
Rank: 11 (945 entries) J |
|||
Rank: 12 (935 entries) REXX |
|||
Rank: 13 (930 entries) Tcl |
|||
Rank: 14 (910 entries) Java |
|||
Rank: 15 (904 entries) Ruby |
|||
</pre> |
|||
Recent, occasionally (hourly-ish) updated output also available at: |
|||
http://www.timb.net/popular-languages.html. |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
===Raku: Using the API=== |
|||
Note that this counts '''only''' the tasks. It does not include other non-task categories in the counts yielding more realistic, non-inflated numbers. Raku is Unicode aware and handles non-ASCII names natively. This does not attempt to 'unify' different language names that are the same behind the scenes as a result of Rosettacodes' capitalization peculiarities. (E.G. μC++, UC++ & ΜC++) |
|||
<syntaxhighlight lang="raku" line>use HTTP::UserAgent; |
|||
use URI::Escape; |
|||
use JSON::Fast; |
|||
use Sort::Naturally; |
|||
my $client = HTTP::UserAgent.new; |
|||
my $url = 'https://rosettacode.org/w'; |
|||
my $tablefile = './RC_Popularity.txt'; |
|||
my %cat = ( |
|||
'Programming_Tasks' => 'Task', |
|||
'Draft_Programming_Tasks' => 'Draft' |
|||
); |
|||
my %tasks; |
|||
for %cat.keys.sort -> $cat { |
|||
mediawiki-query( |
|||
$url, 'pages', |
|||
:generator<categorymembers>, |
|||
:gcmtitle("Category:$cat"), |
|||
:gcmlimit<350>, |
|||
:rawcontinue(), |
|||
:prop<title> |
|||
).map({ %tasks{%cat{$cat}}++ }); |
|||
} |
|||
my %counts = |
|||
mediawiki-query( |
|||
$url, 'pages', |
|||
:generator<categorymembers>, |
|||
:gcmtitle<Category:Programming Languages>, |
|||
:gcmlimit<350>, |
|||
:rawcontinue(), |
|||
:prop<categoryinfo> |
|||
) |
|||
.map({ |
|||
my $title = .<title>.subst(/^'Category:'/, ''); |
|||
my $tasks = (.<categoryinfo><pages> || 0); |
|||
my $categories = (.<categoryinfo><subcats> || 0); |
|||
my $total = (.<categoryinfo><size> || 0); |
|||
$title => [$tasks ,$categories, $total] |
|||
}); |
|||
my $out = open($tablefile, :w) or die "$!\n"; |
|||
# Add table boilerplate and header |
|||
$out.say: |
|||
"\{|class=\"wikitable sortable\"\n", |
|||
"|+ As of { Date.today } :: {+%counts} Languages\n", |
|||
'!Rank!!Language!!Task<br>Entries!!Tasks<br>done %!!Non-task<br>Subcate-<br>gories!!Total<br>Categories' |
|||
; |
|||
my @bg = <#fff; #ccc;>; |
|||
my $ff = 0; |
|||
my $rank = 1; |
|||
my $ties = 0; |
|||
# Get sorted unique task counts |
|||
for %counts.values»[0].unique.sort: -* -> $count { |
|||
$ff++; |
|||
# Get list of tasks with this count |
|||
my @these = %counts.grep( *.value[0] == $count )».keys.sort: *.&naturally; |
|||
for @these { |
|||
$ties++; |
|||
$out.say: |
|||
"|- style=\"background-color: { @bg[$ff % 2] }\"\n"~ |
|||
"|$rank\n"~ |
|||
"|[[:Category:$_|]]\n"~ |
|||
"|$count\n"~ |
|||
"|{(100 * $count/%tasks<Draft Task>.sum).round(.01)} %\n"~ |
|||
"|{%counts{$_}[1]}\n"~ |
|||
"|{%counts{$_}[2]}" |
|||
} |
|||
$rank += $ties; |
|||
$ties = 0; |
|||
} |
|||
$out.say( "|}" ); |
|||
$out.say('=' x 5, " query, download & processing: {(now - INIT now).round(.01)} seconds ", '=' x 5); |
|||
$out.close; |
|||
sub mediawiki-query ($site, $type, *%query) { |
|||
my $url = "$site/api.php?" ~ uri-query-string( |
|||
:action<query>, :format<json>, :formatversion<2>, |%query); |
|||
my $continue = ''; |
|||
gather loop { |
|||
my $response = $client.get("$url&$continue"); |
|||
my $data = from-json($response.content); |
|||
take $_ for $data.<query>.{$type}.values; |
|||
$continue = uri-query-string |($data.<query-continue>{*}».hash.hash or last); |
|||
} |
|||
} |
|||
sub uri-query-string (*%fields) { |
|||
join '&', %fields.map: { "{.key}={uri-escape .value}" } |
|||
}</syntaxhighlight> |
|||
{{out|Abridged output}} See [[Rosetta_Code/Rank_languages_by_popularity/Full_list|full output here]]. |
|||
{|class="wikitable sortable" |
|||
|+ As of 2019-02-10 :: 715 Languages |
|||
!Rank!!Language!!Task<br>Entries!!Tasks<br>done %!!Non-task<br>Subcate-<br>gories!!Total<br>Categories |
|||
|- style="background-color: #ccc;" |
|||
|1 |
|||
|[[:Category:Go|Go]] |
|||
|1100 |
|||
|96.15 % |
|||
|4 |
|||
|1104 |
|||
|- style="background-color: #fff;" |
|||
|2 |
|||
|[[:Category:Perl 6|Perl 6]] |
|||
|1046 |
|||
|91.43 % |
|||
|4 |
|||
|1050 |
|||
|- style="background-color: #ccc;" |
|||
|3 |
|||
|[[:Category:Kotlin|Kotlin]] |
|||
|1029 |
|||
|89.95 % |
|||
|1 |
|||
|1030 |
|||
|- style="background-color: #fff;" |
|||
|4 |
|||
|[[:Category:Python|Python]] |
|||
|1017 |
|||
|88.9 % |
|||
|17 |
|||
|1034 |
|||
|- style="background-color: #ccc;" |
|||
|5 |
|||
|[[:Category:Phix|Phix]] |
|||
|991 |
|||
|86.63 % |
|||
|3 |
|||
|994 |
|||
|- style="background-color: #fff;" |
|||
|6 |
|||
|[[:Category:Racket|Racket]] |
|||
|986 |
|||
|86.19 % |
|||
|3 |
|||
|989 |
|||
|- style="background-color: #ccc;" |
|||
|7 |
|||
|[[:Category:Perl|Perl]] |
|||
|963 |
|||
|84.18 % |
|||
|5 |
|||
|968 |
|||
|- style="background-color: #fff;" |
|||
|8 |
|||
|[[:Category:Julia|Julia]] |
|||
|958 |
|||
|83.74 % |
|||
|3 |
|||
|961 |
|||
|- style="background-color: #ccc;" |
|||
|9 |
|||
|[[:Category:C|C]] |
|||
|940 |
|||
|82.17 % |
|||
|3 |
|||
|943 |
|||
|- style="background-color: #fff;" |
|||
|10 |
|||
|[[:Category:Tcl|Tcl]] |
|||
|925 |
|||
|80.86 % |
|||
|4 |
|||
|929 |
|||
|- style="background-color: #ccc;" |
|||
|11 |
|||
|[[:Category:Zkl|Zkl]] |
|||
|918 |
|||
|80.24 % |
|||
|1 |
|||
|919 |
|||
|- style="background-color: #fff;" |
|||
|12 |
|||
|[[:Category:J|J]] |
|||
|901 |
|||
|78.76 % |
|||
|3 |
|||
|904 |
|||
|- style="background-color: #ccc;" |
|||
|13 |
|||
|[[:Category:Java|Java]] |
|||
|897 |
|||
|78.41 % |
|||
|3 |
|||
|900 |
|||
|- style="background-color: #fff;" |
|||
|14 |
|||
|[[:Category:REXX|REXX]] |
|||
|886 |
|||
|77.45 % |
|||
|4 |
|||
|890 |
|||
|- style="background-color: #ccc;" |
|||
|15 |
|||
|[[:Category:D|D]] |
|||
|871 |
|||
|76.14 % |
|||
|3 |
|||
|874 |
|||
|- style="background-color: #fff;" |
|||
|16 |
|||
|[[:Category:Ruby|Ruby]] |
|||
|866 |
|||
|75.7 % |
|||
|3 |
|||
|869 |
|||
|- style="background-color: #ccc;" |
|||
|17 |
|||
|[[:Category:Haskell|Haskell]] |
|||
|849 |
|||
|74.21 % |
|||
|3 |
|||
|852 |
|||
|- style="background-color: #fff;" |
|||
|18 |
|||
|[[:Category:Scala|Scala]] |
|||
|789 |
|||
|68.97 % |
|||
|3 |
|||
|792 |
|||
|- style="background-color: #ccc;" |
|||
|19 |
|||
|[[:Category:Sidef|Sidef]] |
|||
|787 |
|||
|68.79 % |
|||
|1 |
|||
|788 |
|||
|- style="background-color: #fff;" |
|||
|20 |
|||
|[[:Category:PicoLisp|PicoLisp]] |
|||
|772 |
|||
|67.48 % |
|||
|3 |
|||
|775 |
|||
|} |
|||
===Raku: Using web scraping=== |
|||
Scraping the languages and categories pages. Raku automatically handles Unicode names correctly. |
|||
<syntaxhighlight lang="raku" line>my $languages = qx{wget -O - 'http://rosettacode.org/wiki/Category:Programming_Languages'}; |
|||
my $categories = qx{wget -O - 'http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000'}; |
|||
my @lines = $languages.lines; |
|||
shift @lines until @lines[0] ~~ / '<h2>Subcategories</h2>' /; |
|||
my \languages = set gather for @lines { |
|||
last if / '/bodycontent' /; |
|||
take ~$0 if |
|||
/ '<li><a href="/wiki/Category:' .*? '" title="Category:' .*? '">' (.*?) '</a></li>' /; |
|||
} |
|||
@lines = $categories.lines; |
|||
my @results = sort -*.[0], gather for @lines { |
|||
take [+$1.subst(',', ''), ~$0] if |
|||
/ '<li><a href="/wiki/Category:' .*? '" title="Category:' .*? '">' |
|||
(.*?) <?{ ~$0 ∈ languages }> |
|||
'</a>' .*? '(' (<[, 0..9]>+) ' member' /; |
|||
} |
|||
for @results.kv -> $i, @l { |
|||
printf "%d:\t%4d - %s\n", $i+1, |@l; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
(As of 2018-10-28) Here we show only the top 10. |
|||
<pre>1: 1036 - Go |
|||
2: 1029 - Kotlin |
|||
3: 1014 - Python |
|||
4: 998 - Perl 6 |
|||
5: 980 - Racket |
|||
6: 929 - Tcl |
|||
7: 926 - C |
|||
8: 910 - Perl |
|||
9: 904 - Zkl |
|||
10: 901 - J</pre> |
|||
=={{header|Red}}== |
|||
proccesses only languages with more than 25 entries to keep the list short |
|||
<syntaxhighlight lang="red">Red [] |
|||
data: read http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000 |
|||
lb: make block! 500 |
|||
;;data: read %data.html ;; for testing save html and use flat file |
|||
arr: split data newline |
|||
k: "Category:" |
|||
;; exclude list: |
|||
exrule: [thru ["programming" |
|||
| "users" |
|||
| "Implementations" |
|||
| "Solutions by " |
|||
| "Members" |
|||
| "WikipediaSourced" |
|||
| "Typing/Strong" |
|||
| "Impl needed" |
|||
] |
|||
to end |
|||
] |
|||
foreach line arr [ |
|||
unless find line k [continue] |
|||
parse line [ thru k thru ">" copy lang to "<" to end ] ;; extract/parse language |
|||
if 20 < length? lang [continue] |
|||
if parse lang [exrule] [continue] ;; exclude invalid |
|||
cnt: 0 |
|||
;; parse number of entries |
|||
parse line [thru "</a>" thru "(" copy cnt to " member" (cnt: to-integer cnt ) to end] |
|||
if cnt > 25 [ append lb reduce [to-string lang cnt] ] ;; only process lang with > 25 entries |
|||
] |
|||
lb: sort/skip/compare lb 2 2 ;; sort series by entries |
|||
print reduce [ "Rank Entries Language" ] ;; header |
|||
last: 0 |
|||
rank: 0 |
|||
lb: tail lb ;; process the series backwards |
|||
until [ |
|||
lb: skip lb -2 |
|||
cnt: second lb |
|||
if cnt <> last [ |
|||
rank: rank + 1 |
|||
] |
|||
print rejoin [ pad/left rank 4 "." pad/left cnt 5 " - " first lb ] |
|||
last: cnt |
|||
head? lb ;; until head reached |
|||
] |
|||
</syntaxhighlight> |
|||
Output: (30.12.2017) |
|||
<pre> |
|||
Rank Entries Language |
|||
1. 961 - Racket |
|||
2. 959 - Python |
|||
3. 926 - Perl 6 |
|||
4. 918 - Tcl |
|||
5. 900 - Kotlin |
|||
6. 883 - J |
|||
7. 875 - C |
|||
8. 859 - Zkl |
|||
9. 846 - Ruby |
|||
10. 833 - D |
|||
11. 828 - Go |
|||
12. 812 - REXX |
|||
13. 809 - Haskell |
|||
14. 802 - Java |
|||
15. 785 - Perl |
|||
16. 768 - PicoLisp |
|||
17. 733 - Sidef |
|||
18. 723 - Mathematica |
|||
19. 702 - Julia |
|||
20. 683 - Phix |
|||
21. 668 - C++ |
|||
22. 648 - Ada |
|||
23. 647 - Common Lisp |
|||
24. 637 - C sharp |
|||
25. 621 - AutoHotkey |
|||
</pre> |
|||
=={{header|REXX}}== |
|||
(Native) REXX doesn't support web-page reading, so the aforementioned |
|||
::: ''Rosetta Code categories'' and |
|||
::: ''Rosetta Code languages'' |
|||
<br>were downloaded to local files. |
|||
<br>This program reads the ''Languages'' file and uses the contents of that file for a validation of |
|||
<br>the ''categories'' file. This essentially is a perfect filter for the ''Rosetta Code categories'' file. |
|||
The '''catHeap''' variable in the REXX program is just a long string of all the records in the web-file of the |
|||
<br>Rosetta Code categories, with a special character ('''sep''') that separates each language entry (name). |
|||
The mechanism is to use a (sparse) stemmed array which holds only the names of languages which |
|||
<br>(for most REXXes) uses a hashing algorithm to locate the entry (which is very fast). |
|||
Programming note: (REXX doesn't handle Unicode characters) some special cases that are translated: |
|||
:::* '''╬£C++''' translated into '''µC++''' [Greek micro] |
|||
:::* '''╨£╨Ü-61/52''' translated into '''MK-61/52''' [Cyrillic '''МК-61/52''']) |
|||
:::* '''??-61/52''' translated into '''MK-61/52''' [Cyrillic '''МК-61/52''']) |
|||
:::* '''D├⌐j├á Vu''' translated into '''Déjà Vu''' |
|||
:::* '''Cach├⌐''' translated into '''Caché''' |
|||
:::* '''F┼ìrmul├ª''' translated into '''Fôrmulæ''' |
|||
:::* '''உயிர்/Uyir''' translated into '''Uyir''' |
|||
:::* '''МiniZinc''' translated into '''MiniZinc''' |
|||
(The 3<sup>rd</sup> entry is most likely caused by the inability to render unsupported glyphs when it was first used to add that language.) |
|||
Code was added to support the renaming of the computer programming language '''Perl 6''' ──► '''Raku'''. |
|||
Note that this REXX example properly ranks tied languages. |
|||
This REXX version sorts the tied languages by language name. |
|||
===REXX program=== |
|||
<syntaxhighlight lang="rexx">/*REXX program reads two files and displays a ranked list of Rosetta Code languages.*/ |
|||
parse arg catFID lanFID outFID . /*obtain optional arguments from the CL*/ |
|||
call init /*initialize some REXX variables. */ |
|||
call get /*obtain data from two separate files. */ |
|||
call eSort #,0 /*sort languages along with members. */ |
|||
call tSort /* " " that are tied in rank.*/ |
|||
call eSort #,1 /* " " along with members. */ |
|||
call out /*create the RC_POP.OUT (output) file.*/ |
|||
exit 0 /*stick a fork in it, we're all done. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
commas: parse arg _; do jc=length(_)-3 to 1 by -3; _= insert(",",_,jc); end; return _ |
|||
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*pluralizer.*/ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
eSort: procedure expose #. @. !tr.; arg N,p2; h= N /*sort: number of members*/ |
|||
do while h>1; h= h % 2 /*halve number of records*/ |
|||
do i=1 for N-h; j= i; k= h + i /*sort this part of list.*/ |
|||
if p2 then do while !tR.k==!tR.j & @.k>@.j /*this uses a hard swap ↓*/ |
|||
@= @.j; #= !tR.j; @.j= @.k; !tR.j= !tR.k; @.k= @; !tR.k= # |
|||
if h>=j then leave; j= j - h; k= k - h |
|||
end /*while !tR.k==···*/ |
|||
else do while #.k<#.j /*this uses a hard swap ↓*/ |
|||
@= @.j; #= #.j; @.j= @.k; #.j= #.k; @.k= @; #.k= # |
|||
if h>=j then leave; j= j - h; k= k - h |
|||
end /*while #.k<···*/ |
|||
end /*i*/ /*hard swaps needed for embedded blanks.*/ |
|||
end /*while h>1*/; return |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
get: langs= 0; call rdr 'languages' /*assign languages ───► L.ααα */ |
|||
call rdr 'categories' /*append categories ───► catHeap */ |
|||
#= 0 |
|||
do j=1 until catHeap=='' /*process the heap of categories. */ |
|||
parse var catHeap cat.j (sep) catHeap /*get a category from the catHeap. */ |
|||
parse var cat.j cat.j '<' "(" mems . /*untangle the strange─looking string. */ |
|||
cat.j= space(cat.j); ?=cat.j; upper ? /*remove any superfluous blanks. */ |
|||
if ?=='' | \L.? then iterate /*it's blank or it's not a language. */ |
|||
if pos(',', mems)\==0 then mems= space(translate(mems,,","), 0) /*¬commas.*/ |
|||
if \datatype(mems, 'W') then iterate /*is the "members" number not numeric? */ |
|||
#.0= #.0 + mems /*bump the number of members found. */ |
|||
if u.?\==0 then do; do f=1 for # until ?==@u.f |
|||
end /*f*/ |
|||
#.f= #.f + mems; iterate j /*languages in different cases.*/ |
|||
end /* [↑] handle any possible duplicates.*/ |
|||
u.?= u.? + 1; #= # + 1 /*bump a couple of counters. */ |
|||
#.#= #.# + mems; @.#= cat.j; @u.#=? /*bump the counter; assign it (upper).*/ |
|||
end /*j*/ |
|||
!.=; @tno= '(total) number of' /*array holds indication of TIED langs.*/ |
|||
call tell right(commas(#), 9) @tno 'languages detected in the category file' |
|||
call tell right(commas(langs),9) ' " " " " " " " language " |
|||
call tell right(commas(#.0), 9) @tno 'entries (solutions) detected', , 1; term= 0 |
|||
return /*don't show any more msgs──►term. [↑] */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
init: sep= '█'; L.=0; #.=0; u.=#.; catHeap=; term=1; old.= /*assign some REXX vars*/ |
|||
if catFID=='' then catFID= "RC_POP.CAT" /*Not specified? Then use the default.*/ |
|||
if lanFID=='' then lanFID= "RC_POP.LAN" /* " " " " " " */ |
|||
if outFID=='' then outFID= "RC_POP.OUT" /* " " " " " " */ |
|||
call tell center('timestamp: ' date() time("Civil"),79,'═'), 2, 1; return |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
out: w= length( commas(#) ); rank= 0 /* [↓] show by ascending rank of lang.*/ |
|||
do t=# by -1 for #; rank= rank + 1 /*bump rank of a programming language. */ |
|||
call tell right('rank:' right(commas(!tR.t), w), 20-1) right(!.t, 7), |
|||
right('('commas(#.t) left("entr"s(#.t, 'ies', "y")')', 9), 20) @.t |
|||
end /*#*/ /* [↑] S(···) pluralizes a word. */ |
|||
call tell left('', 27) "☼ end─of─list. ☼", 1, 2; return /*bottom title.*/ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
rdr: arg which 2; igAst= 1 /*ARG uppers WHICH, obtain the 1st char*/ |
|||
if which=='L' then inFID= lanFID /*use this fileID for the languages. */ |
|||
if which=='C' then inFID= catFID /* " " " " " categories. */ |
|||
Uyir= 'உயிர்/Uyir' /*Unicode (in text) name for Uyir */ |
|||
old.0= '╬£C++' ; new.0= "µC++" /*Unicode ╬£C++ ───► ASCII─8: µC++ */ |
|||
old.1= 'UC++' ; new.1= "µC++" /*old UC++ ───► ASCII─8: µC++ */ |
|||
old.2= '╨£╨Ü-' ; new.2= "MK-" /*Unicode ╨£╨Ü─ ───► ASCII-8: MK- */ |
|||
old.3= 'D├⌐j├á' ; new.3= "Déjà" /*Unicode ├⌐j├á ───► ASCII─8: Déjà */ |
|||
old.4= 'Cach├⌐' ; new.4= "Caché" /*Unicode Cach├⌐ ───► ASCII─8: Caché */ |
|||
old.5= '??-61/52' ; new.5= "MK-61/52" /*somewhere past, a mis─translated: MK-*/ |
|||
old.6= 'F┼ìrmul├ª' ; new.6= 'Fôrmulæ' /*Unicode ───► ASCII─8: Fôrmulæ */ |
|||
old.7= '╨£iniZinc' ; new.7= 'MiniZinc' /*Unicode ───► ASCII─8: MiniZinc*/ |
|||
old.8= Uyir ; new.8= 'Uyir' /*Unicode ───► ASCII─8: Uyir */ |
|||
old.9= 'Perl 6' ; new.9= 'Raku' /* (old name) ───► (new name) */ |
|||
do recs=0 while lines(inFID) \== 0 /*read a file, a single line at a time.*/ |
|||
$= translate( linein(inFID), , '9'x) /*handle any stray TAB ('09'x) chars.*/ |
|||
$$= space($); if $$=='' then iterate /*ignore all blank lines in the file(s)*/ |
|||
do v=0 while old.v \== '' /*translate Unicode variations of langs*/ |
|||
if pos(old.v, $$) \==0 then $$= changestr(old.v, $$, new.v) |
|||
end /*v*/ /* [↑] handle different lang spellings*/ |
|||
if igAst then do; igAst= pos(' * ', $)==0; if igAst then iterate; end |
|||
if pos('RETRIEVED FROM', translate($$))\==0 then leave /*pseudo End─Of─Data?.*/ |
|||
if which=='L' then do; if left($$, 1)\=="*" then iterate /*lang ¬legitimate?*/ |
|||
parse upper var $$ '*' $$ "<"; $$= space($$) |
|||
if $$=='' then iterate; L.$$= 1 |
|||
langs= langs + 1 /*bump number of languages found. */ |
|||
iterate |
|||
end /* [↓] extract computer language name.*/ |
|||
if left($$, 1)=='*' then $$= sep || space( substr($$, 2) ) |
|||
catHeap= catHeap $$ /*append to the catHeap (CATegory) heap*/ |
|||
end /*recs*/ |
|||
call tell right( commas(recs), 9) 'records read from file: ' inFID |
|||
return |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
tell: do '0'arg(2); call lineout outFID," " ; if term then say ; end |
|||
call lineout outFID,arg(1) ; if term then say arg(1) |
|||
do '0'arg(3); call lineout outFID," " ; if term then say ; end |
|||
return /*show BEFORE blank lines (if any), message, show AFTER blank lines.*/ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
tSort: tied=; r= 0 /*add true rank (tR) ───► the entries. */ |
|||
do j=# by -1 for #; r= r+1; tR= r; !tR.j= r; jp= j+1; jm= j-1 |
|||
if tied=='' then pR= r; tied= /*handle when language rank is untied. */ |
|||
if #.j==#.jp | #.j==#.jm then do; !.j= '[tied]'; tied= !.j; end |
|||
if #.j==#.jp then do; tR= pR; !tR.j= pR; end |
|||
else pR= r |
|||
end /*j*/; return</syntaxhighlight> |
|||
===all ranked 813 languages=== |
|||
The '''output''' for this REXX (RC_POP.REX) program is included here ──► [[RC_POP.OUT]]. |
|||
[See the talk page about some programming languages using different cases (lower/upper/mixed) for the language names, |
|||
<br>as well as those that use Unicode characters in the name.] <br><br><br> |
|||
=={{header|Ring}}== |
|||
<syntaxhighlight lang="ring"> |
|||
# Project: Rosetta Code/Rank languages by popularity |
|||
load "stdlib.ring" |
|||
ros= download("http://rosettacode.org/wiki/Category:Programming_Languages") |
|||
pos = 1 |
|||
totalros = 0 |
|||
rosname = "" |
|||
rosnameold = "" |
|||
rostitle = "" |
|||
roslist = [] |
|||
for n = 1 to len(ros) |
|||
nr = searchstring(ros,'<li><a href="/wiki/',pos) |
|||
if nr = 0 |
|||
exit |
|||
else |
|||
pos = nr + 1 |
|||
ok |
|||
nr = searchname(nr) |
|||
nr = searchtitle(nr) |
|||
next |
|||
roslist = sortfirst(roslist) |
|||
roslist = reverse(roslist) |
|||
see nl |
|||
for n = 1 to len(roslist) |
|||
see "rank: " + n + " (" + roslist[n][1] + " entries) " + roslist[n][2] + nl |
|||
next |
|||
func searchstring(str,substr,n) |
|||
newstr=right(str,len(str)-n+1) |
|||
nr = substr(newstr, substr) |
|||
if nr = 0 |
|||
return 0 |
|||
else |
|||
return n + nr -1 |
|||
ok |
|||
func count(cstring,dstring) |
|||
sum = 0 |
|||
while substr(cstring,dstring) > 0 |
|||
sum = sum + 1 |
|||
cstring = substr(cstring,substr(cstring,dstring)+len(string(sum))) |
|||
end |
|||
return sum |
|||
func searchname(sn) |
|||
nr2 = searchstring(ros,"/wiki/Category:",sn) |
|||
nr3 = searchstring(ros,"title=",sn) |
|||
nr4 = searchstring(ros,'">',sn) |
|||
nr5 = searchstring(ros,"</a></li>",sn) |
|||
rosname = substr(ros,nr2+15,nr3-nr2-17) |
|||
rosnameold = substr(ros,nr4+2,nr5-nr4-2) |
|||
return sn |
|||
func searchtitle(sn) |
|||
rostitle = "rosettacode.org/wiki/Category:" + rosname |
|||
rostitle = download(rostitle) |
|||
nr2 = 0 |
|||
roscount = count(rostitle,"The following") |
|||
if roscount > 0 |
|||
rp = 1 |
|||
for rc = 1 to roscount |
|||
nr2 = searchstring(rostitle,"The following",rp) |
|||
rp = nr2 + 1 |
|||
next |
|||
ok |
|||
nr3 = searchstring(rostitle,"pages are in this category",nr2) |
|||
if nr2 > 0 and nr3 > 0 |
|||
rosnr = substr(rostitle,nr2+14,nr3-nr2-15) |
|||
rosnr = substr(rosnr,",","") |
|||
add(roslist,[rosnr,rosnameold]) |
|||
ok |
|||
return sn |
|||
func sortfirst(alist) |
|||
for n = 1 to len(alist) - 1 |
|||
for m = n + 1 to len(alist) |
|||
if alist[m][1] < alist[n][1] |
|||
swap(alist,m,n) |
|||
ok |
|||
if alist[m][1] = alist[n][1] and strcmp(alist[m][2],alist[n][2]) > 0 |
|||
swap(alist,m,n) |
|||
ok |
|||
next |
|||
next |
|||
return alist |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
rank: 1 (1010 entries) Kotlin |
|||
rank: 2 (977 entries) Racket |
|||
rank: 3 (968 entries) Python |
|||
rank: 4 (962 entries) Perl 6 |
|||
rank: 5 (931 entries) Go |
|||
rank: 6 (914 entries) Tcl |
|||
rank: 7 (905 entries) C |
|||
rank: 8 (888 entries) J |
|||
rank: 9 (882 entries) Zkl |
|||
rank: 10 (875 entries) Java |
|||
...... |
|||
rank: 30 (580 entries) Ring |
|||
...... |
|||
rank: 523 (2 entries) TechBASIC |
|||
rank: 524 (2 entries) Thyrd |
|||
rank: 525 (2 entries) ToffeeScript |
|||
rank: 526 (2 entries) Viua VM assembly |
|||
rank: 527 (2 entries) XL |
|||
rank: 528 (2 entries) XProc |
|||
rank: 529 (2 entries) XSLT 1.0 |
|||
rank: 530 (2 entries) XTalk |
|||
rank: 531 (2 entries) XUL |
|||
rank: 532 (2 entries) ZPL |
|||
</pre> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
===By using the API=== |
|||
{{works with|Ruby|1.8.7}} |
|||
Now that there are more than 500 categories, the URL given in the task description is insufficient. I use the RC API to grab the categories, and then count the members of each category. |
|||
Uses the <code>RosettaCode</code> module from [[Count programming examples#Ruby]] |
|||
<lang ruby>require 'open-uri' |
|||
<syntaxhighlight lang="ruby">require 'rosettacode' |
|||
langs = [] |
|||
RosettaCode.category_members("Programming Languages") {|lang| langs << lang} |
|||
# API has trouble with long titles= values. |
|||
open("http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=500") do |f| |
|||
# To prevent skipping languages, use short slices of 20 titles. |
|||
for line in f |
|||
langcount = {} |
|||
match = line.match(%r{>([^<>]*)</a> \((\d+) members?\)}) |
|||
langs.each_slice(20) do |sublist| |
|||
entries << match[2] + ' - ' + match[1] if match |
|||
url = RosettaCode.get_api_url({ |
|||
"action" => "query", |
|||
"prop" => "categoryinfo", |
|||
"format" => "xml", |
|||
"titles" => sublist.join("|"), |
|||
}) |
|||
doc = REXML::Document.new open(url) |
|||
REXML::XPath.each(doc, "//page") do |page| |
|||
lang = page.attribute("title").value |
|||
info = REXML::XPath.first(page, "categoryinfo") |
|||
langcount[lang] = info.nil? ? 0 : info.attribute("pages").value.to_i |
|||
end |
end |
||
end |
end |
||
puts Time.now |
|||
entries.sort_by {|x| -x.to_i}.each_with_index do |line, c| |
|||
puts "There are #{langcount.length} languages" |
|||
puts "%3d. %s" % [c+1, line] |
|||
puts "the top 25:" |
|||
end</lang> |
|||
langcount.sort_by {|key,val| val}.reverse[0,25].each_with_index do |(lang, count), i| |
|||
puts "#{i+1}. #{count} - #{lang.sub(/Category:/, '')}" |
|||
end</syntaxhighlight> |
|||
{{out|Results}} |
|||
<pre style="height: 40ex; overflow: scroll">2010-07-08 14:52:46 -0500 |
|||
There are 306 languages |
|||
the top 25: |
|||
1. 399 - Tcl |
|||
2. 370 - Python |
|||
3. 352 - Ruby |
|||
4. 338 - J |
|||
5. 337 - C |
|||
6. 333 - PicoLisp |
|||
7. 322 - OCaml |
|||
8. 322 - Haskell |
|||
9. 299 - Perl |
|||
10. 299 - AutoHotkey |
|||
11. 288 - Common Lisp |
|||
12. 280 - Java |
|||
13. 275 - Ada |
|||
14. 270 - D |
|||
15. 267 - Oz |
|||
16. 253 - R |
|||
17. 252 - PureBasic |
|||
18. 245 - E |
|||
19. 243 - C++ |
|||
20. 241 - C sharp |
|||
21. 239 - ALGOL 68 |
|||
22. 236 - JavaScript |
|||
23. 221 - Forth |
|||
24. 207 - Clojure |
|||
25. 201 - Fortran</pre> |
|||
=={{header|Run BASIC}}== |
|||
<syntaxhighlight lang="runbasic">sqliteconnect #mem, ":memory:" ' make memory DB |
|||
#mem execute("CREATE TABLE stats(lang,cnt)") |
|||
a$ = httpGet$("http://rosettacode.org/wiki/Category:Programming_Languages") |
|||
aa$ = httpGet$("http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000") |
|||
i = instr(a$,"/wiki/Category:") |
|||
while i > 0 and lang$ <> "Languages" |
|||
j = instr(a$,"""",i) |
|||
lang$ = mid$(a$,i+15,j - i-15) |
|||
ii = instr(aa$,"Category:";lang$;"""") |
|||
jj = instr(aa$,"(",ii) |
|||
kk = instr(aa$," ",jj+1) |
|||
if ii = 0 then cnt = 0 else cnt = val(mid$(aa$,jj+1,kk-jj)) |
|||
k = instr(lang$,"%") ' convert hex values to characters |
|||
while k > 0 |
|||
lang$ = left$(lang$,k-1) + chr$(hexdec(mid$(lang$,k+1,2))) + mid$(lang$,k+3) |
|||
k = instr(lang$,"%") |
|||
wend |
|||
#mem execute("insert into stats values ('";lang$;"',";cnt;")") |
|||
i = instr(a$,"/wiki/Category:",i+10) |
|||
wend |
|||
html "<table border=2>" |
|||
#mem execute("SELECT * FROM stats ORDER BY cnt desc") ' order list by count descending |
|||
WHILE #mem hasanswer() |
|||
#row = #mem #nextrow() |
|||
rank = rank + 1 |
|||
html "<TR><TD align=right>";rank;"</td><td>";#row lang$();"</td><td align=right>";#row cnt();"</td></tr>" |
|||
WEND |
|||
html "</table>"</syntaxhighlight> |
|||
<table border=2> |
|||
<TR><TD align=right>1</td><td>Tcl</td><td align=right>687</td></tr> |
|||
<TR><TD align=right>2</td><td>Python</td><td align=right>650</td></tr> |
|||
<TR><TD align=right>3</td><td>C</td><td align=right>638</td></tr> |
|||
<TR><TD align=right>4</td><td>PicoLisp</td><td align=right>626</td></tr> |
|||
<TR><TD align=right>5</td><td>J</td><td align=right>619</td></tr> |
|||
<TR><TD align=right>6</td><td>Go</td><td align=right>587</td></tr> |
|||
<TR><TD align=right>7</td><td>Ruby</td><td align=right>581</td></tr> |
|||
<TR><TD align=right>8</td><td>D</td><td align=right>571</td></tr> |
|||
<TR><TD align=right>9</td><td>Ada</td><td align=right>559</td></tr> |
|||
<TR><TD align=right>10</td><td>Mathematica</td><td align=right>551</td></tr> |
|||
<TR><TD align=right>11</td><td>Perl</td><td align=right>528</td></tr> |
|||
<TR><TD align=right>12</td><td>Perl_6</td><td align=right>528</td></tr> |
|||
<TR><TD align=right>13</td><td>Haskell</td><td align=right>526</td></tr> |
|||
<TR><TD align=right>14</td><td>BBC_BASIC</td><td align=right>513</td></tr> |
|||
<TR><TD align=right>15</td><td>REXX</td><td align=right>491</td></tr> |
|||
<TR><TD align=right>16</td><td>Java</td><td align=right>488</td></tr> |
|||
<TR><TD align=right>17</td><td>OCaml</td><td align=right>477</td></tr> |
|||
<TR><TD align=right>18</td><td>PureBasic</td><td align=right>469</td></tr> |
|||
<TR><TD align=right>19</td><td>Unicon</td><td align=right>462</td></tr> |
|||
<TR><TD align=right>20</td><td>AutoHotkey</td><td align=right>430</td></tr> |
|||
<TR><TD align=right>21</td><td>Icon</td><td align=right>429</td></tr> |
|||
<TR><TD align=right>22</td><td>Common_Lisp</td><td align=right>424</td></tr> |
|||
<TR><TD align=right>23</td><td>C_sharp</td><td align=right>416</td></tr> |
|||
<TR><TD align=right>24</td><td>C++</td><td align=right>400</td></tr> |
|||
<TR><TD align=right>25</td><td>JavaScript</td><td align=right>359</td></tr> |
|||
<TR><TD align=right>26</td><td>Scala</td><td align=right>339</td></tr> |
|||
<TR><TD align=right>27</td><td>PARI/GP</td><td align=right>338</td></tr> |
|||
<TR><TD align=right>28</td><td>Clojure</td><td align=right>335</td></tr> |
|||
<TR><TD align=right>29</td><td>R</td><td align=right>322</td></tr> |
|||
<TR><TD align=right>n</td><td>...</td><td align=right>...</td></tr></table> |
|||
=={{header|Scala}}== |
|||
===Parallel internet querying=== |
|||
Entry point @ object <code>GhettoParserPar</code> |
|||
<syntaxhighlight lang="scala">import akka.actor.{Actor, ActorSystem, Props} |
|||
import scala.collection.immutable.TreeSet |
|||
import scala.xml.XML |
|||
// Reports a list with all languages recorded in the Wiki |
|||
private object Acquisition { |
|||
val (endPoint, prefix) = ("http://rosettacode.org/mw/api.php", "Category:") |
|||
val (maxPlaces, correction) = (50, 2) |
|||
def convertPathArgsToURL(endPoint: String, pathArgs: Map[String, String]) = { |
|||
pathArgs.map(argPair => argPair._1 + "=" + argPair._2) |
|||
.mkString(endPoint + (if (pathArgs.nonEmpty) "?" else ""), "&", "") |
|||
} |
|||
/* The categories include a page for the language and a count of the pages |
|||
* linked therein, this count is the data we need to scrape. |
|||
* Reports a list with language, count pair recorded in the Wiki |
|||
* All strings starts with the prefixes "Category:" |
|||
*/ |
|||
def mineCatos = { |
|||
val endPoint = "http://rosettacode.org/mw/index.php" |
|||
Concurrent.logInfo("Acquisition of categories started.") |
|||
val categories = |
|||
(XML.load(convertPathArgsToURL(endPoint, |
|||
Map("title" -> "Special:Categories", "limit" -> "5000"))) \\ "ul" \ "li") |
|||
.withFilter(p => (p \ "a" \ "@title").text.startsWith(prefix)) |
|||
.map // Create a tuple pair, eg. ("Category:Erlang", 195) |
|||
{ cat => |
|||
((cat \ "a" \ "@title").text, // Takes the sibling of "a" and extracts the number |
|||
"[0-9]+".r.findFirstIn(cat.child.drop(1).text).getOrElse("0").toInt) |
|||
} |
|||
Concurrent.logInfo(s"Got ${categories.size} categories..") |
|||
categories |
|||
} |
|||
// The languages |
|||
// All strings starts with the prefixes "Category:" |
|||
def mineLangs = { |
|||
Concurrent.logInfo("Acquisition of languages started...") |
|||
def getLangs(first: Boolean = true, continue: String = ""): TreeSet[String] = (first, continue) match { |
|||
case (false, "") => TreeSet[String]() |
|||
case _ => { |
|||
val xml = XML.load(convertPathArgsToURL(endPoint, Map( |
|||
"action" -> "query", |
|||
"list" -> "categorymembers", |
|||
"cmtitle" -> (prefix + "Programming_Languages"), |
|||
"cmlimit" -> "500", |
|||
"rawcontinue" -> "", |
|||
"format" -> "xml", |
|||
"cmcontinue" -> continue))) |
|||
getLangs(false, (xml \\ "query-continue" \ "categorymembers" \ "@cmcontinue").text) ++ (xml \\ "categorymembers" \ "cm").map(c => (c \ "@title").text) |
|||
} |
|||
} |
|||
val languages = getLangs() |
|||
Concurrent.logInfo(s"Got ${languages.size} languages..") |
|||
languages |
|||
} |
|||
def joinRosettaCodeWithLanguage(catos: Seq[(String, Int)], |
|||
langs: TreeSet[String]) = |
|||
for { |
|||
cato <- catos //Clean up the tuple pairs, eg ("Category:Erlang", 195) becomes ("Erlang", 192) |
|||
if langs.contains(cato._1) |
|||
} yield (cato._1.drop(prefix.length), cato._2 - correction max 0) // Correct count |
|||
def printScrape(languages: TreeSet[String], category: Seq[(String, Int)]) { |
|||
val join = joinRosettaCodeWithLanguage(category, languages) |
|||
val total = join.foldLeft(0)(_ + _._2) |
|||
Concurrent.logInfo("Data processed") |
|||
println(f"\nTop$maxPlaces%3d Rosetta Code Languages by Popularity as ${new java.util.Date}%tF:\n") |
|||
(join.groupBy(_._2).toSeq.sortBy(-_._1).take(maxPlaces) :+ (0, Seq(("...", 0)))) |
|||
.zipWithIndex // Group the ex aequo |
|||
.foreach { |
|||
case ((score, langs), rank) => |
|||
println(f"${rank + 1}%2d. $score%3d - ${langs.map(_._1).mkString(", ")}") |
|||
} |
|||
println(s"\nCross section yields ${join.size} languages, total of $total solutions") |
|||
println(s"Resulting average is ${total / join.size} solutions per language") |
|||
} |
|||
def printScrape(): Unit = printScrape(mineLangs, mineCatos) |
|||
} // object Acquisition |
|||
private object Concurrent extends AppCommons { |
|||
var (category: Option[Seq[(String, Int)]], language: Option[TreeSet[String]]) = (None, None) |
|||
class Worker extends Actor { |
|||
def receive = { |
|||
case 'Catalogue => sender ! Acquisition.mineCatos |
|||
case 'Language => sender ! Acquisition.mineLangs |
|||
} |
|||
} |
|||
class Listener extends Actor { |
|||
// Create and signal the worker actors |
|||
context.actorOf(Props[Worker], "worker0") ! 'Catalogue |
|||
context.actorOf(Props[Worker], "worker1") ! 'Language |
|||
def printCompleteScape() = |
|||
if (category.isDefined && language.isDefined) { |
|||
Acquisition.printScrape(language.get, category.get) |
|||
context.system.shutdown() |
|||
appEnd() |
|||
} |
|||
def receive = { |
|||
case content: TreeSet[String] => |
|||
language = Some(content) |
|||
printCompleteScape() |
|||
case content: Seq[(String, Int)] => |
|||
category = Some(content) |
|||
printCompleteScape() |
|||
case whatever => logInfo(whatever.toString) |
|||
} // def receive |
|||
} |
|||
} // object Concurrent |
|||
trait AppCommons { |
|||
val execStart = System.currentTimeMillis() |
|||
System.setProperty("http.agent", "*") |
|||
def logInfo(info: String) { |
|||
println(f"[Info][${System.currentTimeMillis() - execStart}%5d ms]" + info) |
|||
} |
|||
def appEnd() { logInfo("Run succesfully completed") } |
|||
} |
|||
// Main entry for sequential version (slower) |
|||
object GhettoParserSeq extends App with AppCommons { |
|||
Concurrent.logInfo("Sequential version started") |
|||
Acquisition.printScrape() |
|||
appEnd() |
|||
} |
|||
// Entry for parallel version (faster) |
|||
object GhettoParserPar extends App { |
|||
Concurrent.logInfo("Parallel version started") |
|||
ActorSystem("Main").actorOf(Props[Concurrent.Listener]) |
|||
}</syntaxhighlight> |
|||
===Sequential internet querying=== |
|||
The same code above but as entry point object <code>GhettoParserSeq</code> |
|||
{{Out|Output for both solutions}} but parallel run chosen. Notice the synchronous start time. |
|||
<pre>[Info][ 0 ms]Sequential version started |
|||
[Info][ 3 ms]Acquisition of languages started... |
|||
[Info][ 1458 ms]Got 642 languages.. |
|||
[Info][ 1458 ms]Acquisition of categories started. |
|||
[Info][19385 ms]Got 2647 categories.. |
|||
[Info][19389 ms]Data processed |
|||
Top 50 Rosetta Code Languages by Popularity as 2016-11-11: |
|||
1. 907 - Racket |
|||
2. 896 - Python, Tcl |
|||
3. 859 - J |
|||
4. 846 - Perl 6 |
|||
5. 810 - Ruby |
|||
6. 807 - Zkl |
|||
7. 795 - C |
|||
8. 774 - Java |
|||
9. 773 - Go |
|||
10. 754 - Haskell |
|||
11. 753 - Perl |
|||
12. 751 - REXX |
|||
13. 750 - D |
|||
14. 729 - PicoLisp |
|||
15. 689 - Mathematica |
|||
16. 674 - Sidef |
|||
17. 634 - C++ |
|||
18. 631 - Ada |
|||
19. 609 - AutoHotkey |
|||
20. 592 - Common Lisp |
|||
21. 583 - Unicon |
|||
22. 569 - Scala |
|||
23. 560 - C sharp |
|||
24. 546 - BBC BASIC |
|||
25. 526 - Icon |
|||
26. 522 - Clojure |
|||
27. 520 - JavaScript |
|||
28. 519 - OCaml |
|||
29. 517 - PureBasic |
|||
30. 513 - PARI/GP |
|||
31. 510 - Lua |
|||
32. 509 - Nim |
|||
33. 497 - ALGOL 68 |
|||
34. 491 - Elixir |
|||
35. 488 - Fortran |
|||
36. 474 - Erlang |
|||
37. 430 - PowerShell |
|||
38. 428 - Julia |
|||
39. 414 - Jq |
|||
40. 413 - F Sharp |
|||
41. 409 - Phix |
|||
42. 407 - Pascal |
|||
43. 405 - Forth, Seed7 |
|||
44. 398 - PL/I |
|||
45. 383 - R |
|||
46. 382 - PHP |
|||
47. 377 - Groovy |
|||
48. 370 - AWK |
|||
49. 340 - MATLAB |
|||
50. 333 - Liberty BASIC |
|||
51. 0 - ... |
|||
Cross section yields 619 languages, total of 50835 solutions |
|||
Resulting average is 82 solutions per language |
|||
[Info][19413 ms]Run succesfully completed</pre> |
|||
=={{header|Seed7}}== |
|||
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
|||
include "gethttp.s7i"; |
|||
include "scanstri.s7i"; |
|||
const type: popularityHash is hash [string] integer; |
|||
const type: rankingHash is hash [integer] array string; |
|||
const func array string: getLangs (in string: buffer) is func |
|||
result |
|||
var array string: langs is 0 times ""; |
|||
local |
|||
var integer: pos is 0; |
|||
begin |
|||
pos := pos(buffer, "Category:"); |
|||
while pos <> 0 do |
|||
pos +:= 9; |
|||
langs &:= buffer[pos .. pred(pos(buffer, '"', pos))]; |
|||
pos := pos(buffer, "Category:", pos); |
|||
end while; |
|||
end func; |
|||
const proc: main is func |
|||
local |
|||
var string: categories is ""; |
|||
var popularityHash: popularity is popularityHash.value; |
|||
var rankingHash: ranking is rankingHash.value; |
|||
var array integer: numList is 0 times 0; |
|||
var string: lang is ""; |
|||
var integer: pos is 0; |
|||
var string: numStri is ""; |
|||
var integer: listIdx is 0; |
|||
var integer: index is 0; |
|||
var integer: place is 1; |
|||
begin |
|||
categories := getHttp("www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000"); |
|||
for lang range getLangs(getHttp("rosettacode.org/mw/api.php?action=query&list=categorymembers&\ |
|||
\cmtitle=Category:Programming_Languages&cmlimit=500&format=json")) do |
|||
pos := pos(categories, "title=\"Category:" & lang); |
|||
if pos <> 0 then |
|||
pos := pos(categories, "</a>", succ(pos)); |
|||
if pos <> 0 then |
|||
pos := pos(categories, "(", succ(pos)); |
|||
if pos <> 0 then |
|||
numStri := categories[succ(pos) len 10]; |
|||
popularity @:= [lang] integer parse getDigits(numStri); |
|||
end if; |
|||
end if; |
|||
end if; |
|||
end for; |
|||
ranking := flip(popularity); |
|||
numList := sort(keys(ranking)); |
|||
for listIdx range maxIdx(numList) downto minIdx(numList) do |
|||
for key index range ranking[numList[listIdx]] do |
|||
writeln(place lpad 3 <& ". " <& numList[listIdx] <& " - " <& ranking[numList[listIdx]][index]); |
|||
end for; |
|||
place +:= length(ranking[numList[listIdx]]); |
|||
end for; |
|||
end func;</syntaxhighlight> |
|||
List of languages as of 2014-01-15: |
|||
<pre> |
|||
1. 772 - Tcl |
|||
2. 733 - Racket |
|||
3. 718 - Python |
|||
4. 685 - C |
|||
5. 657 - Perl 6 |
|||
6. 654 - J |
|||
7. 645 - D |
|||
8. 643 - Ruby |
|||
9. 636 - PicoLisp |
|||
10. 624 - Go |
|||
11. 610 - Perl |
|||
12. 579 - REXX |
|||
13. 578 - Ada |
|||
14. 567 - Mathematica |
|||
14. 567 - Haskell |
|||
16. 532 - Unicon |
|||
17. 526 - Java |
|||
18. 523 - BBC BASIC |
|||
19. 489 - OCaml |
|||
20. 487 - Icon |
|||
21. 477 - C++ |
|||
22. 470 - PureBasic |
|||
23. 448 - Common Lisp |
|||
24. 439 - Erlang |
|||
24. 439 - C sharp |
|||
26. 437 - AutoHotkey |
|||
27. 406 - Scala |
|||
28. 382 - JavaScript |
|||
29. 375 - Clojure |
|||
30. 356 - Seed7 |
|||
... |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
{{trans|Perl}} |
|||
<syntaxhighlight lang="ruby">require('MediaWiki::API') |
|||
var api = %O<MediaWiki::API>.new( |
|||
Hash(api_url => 'http://rosettacode.org/mw/api.php') |
|||
) |
|||
var languages = [] |
|||
var gcmcontinue |
|||
loop { |
|||
var apih = api.api( |
|||
Hash( |
|||
action => 'query', |
|||
generator => 'categorymembers', |
|||
gcmtitle => 'Category:Programming Languages', |
|||
gcmlimit => 250, |
|||
prop => 'categoryinfo', |
|||
gcmcontinue => gcmcontinue, |
|||
) |
|||
) |
|||
languages.append(apih{:query}{:pages}.values...) |
|||
gcmcontinue = apih{:continue}{:gcmcontinue} |
|||
gcmcontinue || break |
|||
} |
|||
languages.each { |lang| |
|||
lang{:title} -= /^Category:/ |
|||
lang{:categoryinfo}{:size} := 0 |
|||
} |
|||
var sorted_languages = languages.sort_by { |lang| |
|||
-lang{:categoryinfo}{:size} |
|||
} |
|||
sorted_languages.each_kv { |i, lang| |
|||
printf("%3d. %20s - %3d\n", i+1, lang{:title}, lang{:categoryinfo}{:size}) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. Racket - 938 |
|||
2. Python - 930 |
|||
3. Tcl - 904 |
|||
4. Perl 6 - 877 |
|||
5. J - 863 |
|||
6. Zkl - 834 |
|||
7. Ruby - 830 |
|||
8. C - 805 |
|||
9. Go - 793 |
|||
10. Haskell - 785 |
|||
11. Java - 783 |
|||
12. REXX - 776 |
|||
13. Perl - 765 |
|||
14. D - 753 |
|||
15. PicoLisp - 731 |
|||
16. Mathematica - 702 |
|||
17. Sidef - 696 |
|||
... |
|||
</pre> |
|||
=={{header|SNOBOL4}}== |
|||
{{Works with|SNOBOL4|CSNOBOL4 CVS test}} |
|||
<syntaxhighlight lang="snobol4">-include "url.sno" |
|||
http.recl = "K,32767" ;* Read next 32767 characters |
|||
;* of very long lines. |
|||
rclangs = "http://rosettacode.org/mw/api.php?" |
|||
+ "format=xml&action=query&generator=categorymembers&" |
|||
+ "gcmtitle=Category:Programming%20Languages&" |
|||
+ "gcmlimit=500&prop=categoryinfo" |
|||
languagepat = arb "<page" arb 'title="Category:' |
|||
+ break('"') . lang arb 'pages="' break('"') . count |
|||
langtable = table(500, 20) |
|||
url.open(.fin, rclangs, http.recl) :s(read) |
|||
output = "Cannot open rosettacode site." :(end) |
|||
read line = line fin :f(done) |
|||
get line languagepat = :f(read) |
|||
langtable<syntaxhighlight lang="text"> = langtable<syntaxhighlight lang="text"> + count :(get) |
|||
done langarray = rsort(langtable,2) :s(write) |
|||
output = "No languages found." :(end) |
|||
write n = n + 1 |
|||
output = lpad(n ". ", 5) lpad(langarray<n, 2>, 4) |
|||
+ " - " langarray<n,1> :s(write) |
|||
url.close(.fin) |
|||
end</syntaxhighlight> |
|||
'''Abridged output (top 30 languages as of August 25, 2015):''' |
|||
<pre> 1. 875 - Racket |
|||
2. 837 - Python |
|||
3. 799 - J |
|||
4. 772 - Ruby |
|||
5. 763 - Perl 6 |
|||
6. 756 - C |
|||
7. 742 - Go |
|||
8. 737 - D |
|||
9. 707 - Perl |
|||
10. 699 - REXX |
|||
11. 689 - PicoLisp |
|||
12. 683 - Haskell |
|||
13. 672 - Mathematica |
|||
14. 650 - Java |
|||
15. 620 - Ada |
|||
16. 588 - AutoHotkey |
|||
17. 563 - C++ |
|||
18. 553 - Common Lisp |
|||
19. 546 - Scala |
|||
20. 529 - BBC BASIC |
|||
21. 520 - Icon |
|||
22. 513 - C sharp |
|||
23. 505 - OCaml |
|||
24. 501 - Nim |
|||
25. 487 - PureBasic |
|||
26. 485 - Clojure |
|||
27. 455 - Epigram |
|||
28. 443 - PARI/GP |
|||
29. 431 - JavaScript |
|||
30. 410 - Jq</pre> |
|||
=={{header|Stata}}== |
|||
First we build the database: |
|||
<syntaxhighlight lang="stata">copy "http://rosettacode.org/wiki/Category:Programming_Languages" lang.html, replace |
|||
import delimited lang.html, delim("@") enc("utf-8") clear |
|||
keep if ustrpos(v1,"/wiki/Category:") |
|||
gen i = ustrpos(v1,"title=") |
|||
gen j = ustrpos(v1,char(34),i+1) |
|||
gen k = ustrpos(v1,char(34),j+1) |
|||
gen s = usubstr(v1,j,k-j+1) |
|||
keep if usubstr(s,2,9)=="Category:" |
|||
gen lang=usubstr(s,11,ustrlen(s)-11) |
|||
keep lang |
|||
save lang, replace |
|||
copy "http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000" categ.html, replace |
|||
import delimited categ.html, delim("@") enc("utf-8") clear |
|||
keep if ustrpos(v1,"/wiki/Category:") & ustrpos(v1,"member") |
|||
gen i = ustrpos(v1,"title=") |
|||
gen j = ustrpos(v1,char(34),i+1) |
|||
gen k = ustrpos(v1,char(34),j+1) |
|||
gen s = usubstr(v1,j,k-j+1) |
|||
keep if usubstr(s,2,9)=="Category:" |
|||
gen lang=usubstr(s,11,ustrlen(s)-11) |
|||
drop i j k s |
|||
gen i = ustrrpos(v1,"(") |
|||
gen j = ustrrpos(v1,")") |
|||
gen s = usubstr(v1,i,j-i+1) |
|||
gen k = ustrpos(s," ") |
|||
gen t = usubstr(s,2,k-1) |
|||
destring t, gen(count) |
|||
drop v1 i j k s t |
|||
merge 1:1 lang using lang, keep(2 3) nogen |
|||
replace count=0 if missing(count) |
|||
gsort -count lang |
|||
gen rank=1 |
|||
replace rank=rank[_n-1]+(count[_n]!=count[_n-1]) in 2/l |
|||
save tasks, replace</syntaxhighlight> |
|||
Now some results, as of 2017-12-03: |
|||
<syntaxhighlight lang="stata">* Total number of entries |
|||
qui sum n |
|||
di r(sum) |
|||
57211 |
|||
* Number of languages |
|||
count |
|||
671 |
|||
* Number of languages with at least one entry |
|||
count if count |
|||
650 |
|||
* First 10 languages |
|||
list in 1/10, noobs |
|||
+-----------------------+ |
|||
| lang count rank | |
|||
|-----------------------| |
|||
| Racket 961 1 | |
|||
| Python 958 2 | |
|||
| Perl 6 925 3 | |
|||
| Tcl 918 4 | |
|||
| J 883 5 | |
|||
|-----------------------| |
|||
| C 874 6 | |
|||
| Kotlin 868 7 | |
|||
| Zkl 857 8 | |
|||
| Ruby 845 9 | |
|||
| Go 828 10 | |
|||
+-----------------------+</syntaxhighlight> |
|||
=={{header|Tcl}}== |
|||
===By web scraping=== |
|||
<syntaxhighlight lang="tcl">package require Tcl 8.5 |
|||
package require http |
|||
set response [http::geturl http://rosettacode.org/mw/index.php?title=Special:Categories&limit=8000] |
|||
array set ignore { |
|||
"Basic language learning" 1 |
|||
"Encyclopedia" 1 |
|||
"Implementations" 1 |
|||
"Language Implementations" 1 |
|||
"Language users" 1 |
|||
"Maintenance/OmitCategoriesCreated" 1 |
|||
"Programming Languages" 1 |
|||
"Programming Tasks" 1 |
|||
"RCTemplates" 1 |
|||
"Solutions by Library" 1 |
|||
"Solutions by Programming Language" 1 |
|||
"Solutions by Programming Task" 1 |
|||
"Unimplemented tasks by language" 1 |
|||
"WikiStubs" 1 |
|||
"Examples needing attention" 1 |
|||
"Impl needed" 1 |
|||
} |
|||
# need substring filter |
|||
proc filterLang {n} { |
|||
return [expr {[string first "User" $n] > 0}] |
|||
} |
|||
# (sorry the 1 double quote in the regexp kills highlighting) |
|||
foreach line [split [http::data $response] \n] { |
|||
if {[regexp {title..Category:([^"]+).* \((\d+) members\)} $line -> lang num]} { |
|||
if {![info exists ignore($lang)] && ![filterLang $lang]} { |
|||
lappend langs [list $num $lang] |
|||
} |
|||
} |
|||
} |
|||
foreach entry [lsort -integer -index 0 -decreasing $langs] { |
|||
lassign $entry num lang |
|||
puts [format "%d. %d - %s" [incr i] $num $lang] |
|||
}</syntaxhighlight> |
|||
{{out|Output on 29 July 2015 (top 20 entries only)}} |
|||
<pre>1. 887 - Tcl |
|||
2. 877 - Racket |
|||
3. 853 - Python |
|||
4. 795 - J |
|||
5. 775 - Ruby |
|||
6. 766 - Perl 6 |
|||
7. 757 - C |
|||
8. 746 - Go |
|||
9. 740 - D |
|||
10. 710 - Perl |
|||
11. 697 - REXX |
|||
12. 692 - PicoLisp |
|||
13. 682 - Haskell |
|||
14. 675 - Mathematica |
|||
15. 652 - Java |
|||
16. 634 - Zkl |
|||
17. 623 - Ada |
|||
18. 591 - AutoHotkey |
|||
19. 581 - Unicon |
|||
20. 562 - C++ |
|||
……</pre> |
|||
===By using the API=== |
|||
{{trans|Ruby}} |
|||
{{works with|Tcl|8.5}} |
|||
{{libheader|tDOM}} |
|||
<syntaxhighlight lang="tcl">package require Tcl 8.5 |
|||
package require http |
|||
package require tdom |
|||
namespace eval rc { |
|||
### Utility function that handles the low-level querying ### |
|||
proc rcq {q xp vn b} { |
|||
upvar 1 $vn v |
|||
dict set q action "query" |
|||
# Loop to pick up all results out of a category query |
|||
while 1 { |
|||
set url "http://rosettacode.org/mw/api.php?[http::formatQuery {*}$q]" |
|||
puts -nonewline stderr . ;# Indicate query progress... |
|||
set token [http::geturl $url] |
|||
set doc [dom parse [http::data $token]] |
|||
http::cleanup $token |
|||
# Spoon out the DOM nodes that the caller wanted |
|||
foreach v [$doc selectNodes $xp] { |
|||
uplevel 1 $b |
|||
} |
|||
# See if we want to go round the loop again |
|||
set next [$doc selectNodes "//query-continue/categorymembers"] |
|||
if {![llength $next]} break |
|||
dict set q cmcontinue [[lindex $next 0] getAttribute "cmcontinue"] |
|||
} |
|||
} |
|||
### API function: Iterate over the members of a category ### |
|||
proc members {page varName script} { |
|||
upvar 1 $varName var |
|||
set query [dict create cmtitle "Category:$page" {*}{ |
|||
list "categorymembers" |
|||
format "xml" |
|||
cmlimit "500" |
|||
}] |
|||
rcq $query "//cm" item { |
|||
# Tell the caller's script about the item |
|||
set var [$item getAttribute "title"] |
|||
uplevel 1 $script |
|||
} |
|||
} |
|||
### API function: Count the members of a list of categories ### |
|||
proc count {cats catVar countVar script} { |
|||
upvar 1 $catVar cat $countVar count |
|||
set query [dict create prop "categoryinfo" format "xml"] |
|||
for {set n 0} {$n<[llength $cats]} {incr n 20} { ;# limit fetch to 20 at a time |
|||
dict set query titles [join [lrange $cats $n $n+19] |] |
|||
rcq $query "//page" item { |
|||
# Get title and count |
|||
set cat [$item getAttribute "title"] |
|||
set info [$item getElementsByTagName "categoryinfo"] |
|||
if {[llength $info]} { |
|||
set count [[lindex $info 0] getAttribute "pages"] |
|||
} else { |
|||
set count 0 |
|||
} |
|||
# Let the caller's script figure out what to do with them |
|||
uplevel 1 $script |
|||
} |
|||
} |
|||
} |
|||
### Assemble the bits into a whole API ### |
|||
namespace export members count |
|||
namespace ensemble create |
|||
} |
|||
# Get the list of programming languages |
|||
rc members "Programming Languages" lang { |
|||
lappend langs $lang |
|||
} |
|||
puts stderr "" ;# Because of the progress dots... |
|||
puts "There are [llength $langs] languages" |
|||
# Get the count of solutions for each, stripping "Category:" prefix |
|||
rc count $langs l c { |
|||
dict set langcounts [regsub {^Category:} $l {}] $c |
|||
} |
|||
puts stderr "" ;# Because of the progress dots... |
|||
# Print the output |
|||
puts "Here are the top fifteen:" |
|||
set langcounts [lsort -stride 2 -index 1 -integer -decreasing $langcounts] |
|||
set i 0 |
|||
foreach {lang count} $langcounts { |
|||
puts [format "%1\$3d. %3\$3d - %2\$s" [incr n] $lang $count] |
|||
if {[incr i]>=15} break |
|||
} |
|||
# --- generate a full report, similar in format to REXX example |
|||
proc popreport {langcounts} { |
|||
set bycount {} |
|||
foreach {lang count} $langcounts { |
|||
dict lappend bycount $count $lang |
|||
} |
|||
set bycount [lsort -stride 2 -integer -decreasing $bycount] |
|||
set rank 1 |
|||
foreach {count langs} $bycount { |
|||
set tied [expr {[llength $langs] > 1 ? "\[tied\]" : ""}] |
|||
foreach lang $langs { |
|||
puts [format {%15s:%4d %-12s %12s %s} rank $rank $tied "($count entries)" $lang] |
|||
} |
|||
incr rank [llength $langs] |
|||
} |
|||
} |
|||
popreport $langcounts</syntaxhighlight> |
|||
{{out}} |
|||
<pre>.. |
|||
There are 582 languages |
|||
.............................. |
|||
Here are the top fifteen: |
|||
1. 882 - Tcl |
|||
2. 874 - Racket |
|||
3. 837 - Python |
|||
4. 790 - J |
|||
5. 772 - Ruby |
|||
6. 762 - Perl 6 |
|||
7. 754 - C |
|||
8. 739 - Go |
|||
9. 736 - D |
|||
10. 706 - Perl |
|||
11. 694 - REXX |
|||
12. 689 - PicoLisp |
|||
13. 679 - Haskell |
|||
14. 672 - Mathematica |
|||
15. 649 - Java</pre> |
|||
Full output is included at [[Rosetta_Code/Rank_languages_by_popularity/Tcl_API_full_output]]. |
|||
=={{header|TUSCRIPT}}== |
|||
<syntaxhighlight lang="tuscript">$$ MODE TUSCRIPT |
|||
remotedata = REQUEST ("http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000") |
|||
allmembers=allnames="" |
|||
COMPILE |
|||
LOOP d=remotedata |
|||
IF (d.sw."<li>") THEN |
|||
name=EXTRACT (d,":<<a<><%>>:"|,":<</a>>:") |
|||
IF (name.eq."Language users") CYCLE |
|||
IF (name.sw."Unimplemented tasks") CYCLE |
|||
IF (name.sw."Programming") CYCLE |
|||
IF (name.sw."Solutions") CYCLE |
|||
IF (name.sw."Garbage") CYCLE |
|||
IF (name.sw."Typing") CYCLE |
|||
IF (name.sw."BASIC LANG") CYCLE |
|||
IF (name.ew."USER") CYCLE |
|||
IF (name.ew."tasks") CYCLE |
|||
IF (name.ew."attention") CYCLE |
|||
IF (name.ew."related") CYCLE |
|||
IF (name.ct."*omit*") CYCLE |
|||
IF (name.ct.":*Categor*:") CYCLE |
|||
IF (name.ct.":WikiSTUBS:") CYCLE |
|||
IF (name.ct.":Impl needed:") CYCLE |
|||
IF (name.ct.":Implementations:") CYCLE |
|||
IF (name.ct.":':") name = EXCHANGE (name,":'::") |
|||
members = STRINGS (d,":><1<>>/><<> member:") |
|||
IF (members!="") THEN |
|||
allmembers=APPEND (allmembers,members) |
|||
allnames =APPEND (allnames,name) |
|||
ENDIF |
|||
ENDIF |
|||
ENDLOOP |
|||
index = DIGIT_INDEX (allmembers) |
|||
index = REVERSE (index) |
|||
allmembers = INDEX_SORT (allmembers,index) |
|||
allnames = INDEX_SORT (allnames, index) |
|||
ERROR/STOP CREATE ("list",SEQ-E,-std-) |
|||
time=time(),balt=nalt="" |
|||
FILE "list" = time |
|||
LOOP n, a=allnames,b=allmembers |
|||
IF (b==balt) THEN |
|||
nr=nalt |
|||
ELSE |
|||
nalt=nr=n |
|||
ENDIF |
|||
content=concat (nr,". ",a," --- ",b) |
|||
FILE "list" = CONTENT |
|||
balt=b |
|||
ENDLOOP |
|||
ENDCOMPILE</syntaxhighlight> |
|||
{{out}} |
|||
<pre style='height:30ex;overflow:scroll'> |
|||
2011-01-24 14:05:27 |
|||
1. Tcl --- 472 member |
|||
2. PicoLisp --- 441 member |
|||
3. Python --- 432 member |
|||
4. J --- 414 member |
|||
5. C --- 394 member |
|||
6. Ruby --- 385 member |
|||
7. PureBasic --- 371 member |
|||
8. Haskell --- 369 member |
|||
9. Ada --- 364 member |
|||
10. OCaml --- 352 member |
|||
11. Perl --- 339 member |
|||
11. D --- 339 member |
|||
13. Java --- 325 member |
|||
14. AutoHotkey --- 308 member |
|||
15. Common Lisp --- 305 membe |
|||
16. C sharp --- 301 member |
|||
17. C++ --- 285 member |
|||
18. Oz --- 278 member |
|||
19. Clojure --- 272 member |
|||
20. R --- 266 member |
|||
21. ALGOL 68 --- 262 member |
|||
22. Perl 6 --- 258 member |
|||
23. JavaScript --- 257 member |
|||
24. E --- 254 member |
|||
25. REXX --- 253 member |
|||
26. Fortran --- 251 member |
|||
27. Forth --- 248 member |
|||
28. Lua --- 238 member |
|||
29. PHP --- 215 member |
|||
30. Unicon --- 211 member |
|||
31. Icon --- 210 member |
|||
32. Factor --- 207 member |
|||
33. Scala --- 197 member |
|||
34. PL/I --- 193 member |
|||
34. Go --- 193 member |
|||
36. Scheme --- 186 member |
|||
</pre> |
|||
=={{header|UnixPipes}}== |
|||
{{libheader|curl}} |
|||
<syntaxhighlight lang="bash">curl 'http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000' | |
|||
sed -nre 's/^<li.*title="Category:([^"(]+)".*\(([0-9]+) members\).*/\2 - \1/p' | |
|||
sort -nr | awk '{printf "%2d. %s\n",NR,$0}'</syntaxhighlight> |
|||
=={{header|VBScript}}== |
|||
Uses the API. Instead of displaying it on the command prompt, the records of the languages are saved on a text file "OutVBRC.txt" encoded with Unicode. |
|||
<syntaxhighlight lang="vb"> ''''''''''''''''''''''''''''''''''''''''''''' |
|||
' Rosetta Code/Rank Languages by Popularity ' |
|||
' VBScript Implementation ' |
|||
'...........................................' |
|||
'API Links (From C Code) |
|||
URL1 = "http://www.rosettacode.org/mw/api.php?format=json&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo&rawcontinue" |
|||
URL2 = "http://www.rosettacode.org/mw/api.php?format=json&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo&gcmcontinue=" |
|||
'Get Contents of the API from the Web... |
|||
Function ScrapeGoat(link) |
|||
On Error Resume Next |
|||
ScrapeGoat = "" |
|||
Err.Clear |
|||
Set objHttp = CreateObject("Msxml2.ServerXMLHTTP") |
|||
objHttp.Open "GET", link, False |
|||
objHttp.Send |
|||
If objHttp.Status = 200 And Err = 0 Then ScrapeGoat = objHttp.ResponseText |
|||
Set objHttp = Nothing |
|||
End Function |
|||
'HACK: Setup HTML for help of my partner/competitor that is better than me, JavaScript... |
|||
Set HTML = CreateObject("HtmlFile") |
|||
Set HTMLWindow = HTML.ParentWindow |
|||
'''''''''''''''''''' |
|||
' Main code begins ' |
|||
'..................' |
|||
On Error Resume Next |
|||
isComplete = 0 ' 1 -> Complete Already |
|||
cntLoop = 0 ' Counts Number of Loops Done |
|||
Set outputData = CreateObject("Scripting.Dictionary") |
|||
Do |
|||
'Scrape Data From API |
|||
If cntLoop = 0 Then strData = ScrapeGoat(URL1) Else strData = ScrapeGoat(URL2 & gcmCont) |
|||
If Len(strData) = 0 Then |
|||
Set HTML = Nothing |
|||
WScript.StdErr.WriteLine "Processing of data stopped because API query failed." |
|||
WScript.Quit(1) |
|||
End If |
|||
'Parse JSON HACK |
|||
HTMLWindow.ExecScript "var json = " & strData, "JavaScript" |
|||
Set ObjJS = HTMLWindow.json |
|||
Err.Clear 'Test if Query is Complete Already |
|||
batchCompl = ObjJS.BatchComplete |
|||
If Err.Number = 438 Then |
|||
'Query not yet complete. Get gcmContinue instead. |
|||
gcmCont = ObjJS.[Query-Continue].CategoryMembers.gcmContinue |
|||
Else |
|||
isComplete = 1 'Yes! |
|||
End If |
|||
'HACK #2: Put all language page ids into a JS array to be accessed by VBScript |
|||
HTMLWindow.ExecScript "var langs=new Array(); for(var lang in json.query.pages){langs.push(lang);}" & _ |
|||
"var nums=langs.length;", "JavaScript" |
|||
Set arrLangs = HTMLWindow.langs |
|||
arrLength = HTMLWindow.nums |
|||
For i = 0 to arrLength - 1 |
|||
BuffStr = "ObjJS.Query.Pages.[" & Eval("arrLangs.[" & i & "]") & "]" |
|||
EachStr = Eval(BuffStr & ".title") |
|||
Err.Clear |
|||
CntLang = Eval(BuffStr & ".CategoryInfo.Pages") |
|||
If InStr(EachStr, "Category:") = 1 And Err.Number = 0 Then |
|||
outputData.Add Replace(EachStr, "Category:", "", 1, 1), CntLang |
|||
End If |
|||
Next |
|||
cntLoop = cntLoop + 1 |
|||
Loop While isComplete = 0 |
|||
'The outputData now contains the data we need. We should now sort and print it! |
|||
'Make a 2D array with copy of outputData |
|||
arrRelease = Array() |
|||
ReDim arrRelease(UBound(outputData.Keys), 1) |
|||
outKeys = outputData.Keys |
|||
outItem = outputData.Items |
|||
For i = 0 To UBound(outKeys) |
|||
arrRelease(i, 0) = outKeys(i) |
|||
arrRelease(i, 1) = outItem(i) |
|||
Next |
|||
'Bubble Sort (Greatest to Least Number of Examples) |
|||
For i = 0 to UBound(arrRelease, 1) |
|||
For j = 0 to UBound(arrRelease, 1) - 1 |
|||
If arrRelease(j, 1) < arrRelease(j + 1, 1) Then |
|||
temp1 = arrRelease(j + 1, 0) |
|||
temp2 = arrRelease(j + 1, 1) |
|||
arrRelease(j + 1, 0) = arrRelease(j, 0) |
|||
arrRelease(j + 1, 1) = arrRelease(j, 1) |
|||
arrRelease(j, 0) = temp1 |
|||
arrRelease(j, 1) = temp2 |
|||
End If |
|||
Next |
|||
Next |
|||
'Save contents to file instead to support Unicode Names |
|||
Set objFSO = CreateObject("Scripting.FileSystemObject") |
|||
Set txtOut = objFSO.CreateTextFile(".\OutVBRC.txt", True, True) |
|||
txtOut.WriteLine "As of " & Now & ", RC has " & UBound(arrRelease) + 1 & " languages." |
|||
txtOut.WriteLine "" |
|||
For i = 0 to UBound(arrRelease) |
|||
txtOut.WriteLine arrRelease(i, 1) & " Examples - " & arrRelease(i, 0) |
|||
Next |
|||
'Successfully Done :) |
|||
Set HTML = Nothing |
|||
Set objFSO = Nothing |
|||
WScript.Quit(0)</syntaxhighlight> |
|||
{{Out|Some Parts of Output as of December 31, 2016}} |
|||
<pre>As of 12/31/2016 11:52:05 PM, RC has 624 languages. |
|||
917 Examples - Racket |
|||
906 Examples - Python |
|||
894 Examples - Tcl |
|||
859 Examples - J |
|||
853 Examples - Perl 6 |
|||
819 Examples - Zkl |
|||
813 Examples - Ruby |
|||
796 Examples - C |
|||
776 Examples - Java |
|||
774 Examples - Go |
|||
766 Examples - Haskell |
|||
760 Examples - REXX |
|||
755 Examples - Perl |
|||
750 Examples - D |
|||
. |
|||
. |
|||
. |
|||
0 Examples - SheerPower 4GL |
|||
0 Examples - Script Basic |
|||
0 Examples - VRML |
|||
0 Examples - Thistle |
|||
0 Examples - UserRPL |
|||
0 Examples - WML |
|||
0 Examples - VAX Assembly</pre> |
|||
=={{header|Visual Basic .NET}}== |
|||
Uses Web scrapping to get the information from the Languages category page - as this now shows the number of pages in each category with the non-task pages separated, there is no need to access other pages.<br> |
|||
It may be necessary to set the Security Protocol to Tls12 at the start of the Main method in order to run this - see the "Problem running the C# entry" section on the [[Talk:Rosetta Code/Count examples]] page. |
|||
<syntaxhighlight lang="vbnet"> |
|||
Imports System.Collections |
|||
Imports System.Collections.Generic |
|||
Imports System.Net |
|||
Imports System.Text.RegularExpressions |
|||
Module RankLanguagesByPopularity |
|||
Private Class LanguageStat |
|||
Public name As String |
|||
Public count As Integer |
|||
Public Sub New(name As String, count As Integer) |
|||
Me.name = name |
|||
Me.count = count |
|||
End Sub |
|||
End Class |
|||
Private Function CompareLanguages(x As LanguageStat, y As languageStat) As Integer |
|||
Dim result As Integer = 0 |
|||
If x IsNot Nothing Or y IsNot Nothing Then |
|||
If x Is Nothing Then |
|||
result = -1 |
|||
ElseIf y Is Nothing |
|||
result = 1 |
|||
Else |
|||
result = - x.count.CompareTo(y.count) ' Sort descending count |
|||
If result = 0 Then |
|||
result = x.name.CompareTo(y.name) ' Sort ascending name |
|||
End If |
|||
End If |
|||
End If |
|||
Return result |
|||
End Function |
|||
Public Sub Main(ByVal args As String()) |
|||
Dim languages As New List(Of LanguageStat) |
|||
Dim basePage As String = "https://rosettacode.org/wiki/Category:Programming_Languages" |
|||
Dim nextPage As String = basePage |
|||
Dim nextPageEx = New RegEx("<a href=""/wiki/Category:Programming_Languages([?]subcatfrom=[^""]*)""") |
|||
Dim languageStatEx = _ |
|||
New Regex(">([^<]+?)</a>[^<]*<span title=""Contains *[0-9,.]* *[a-z]*, *([0-9,.]*) *page") |
|||
Do While nextPage <> "" |
|||
Dim wc As New WebClient() |
|||
Dim page As String = wc.DownloadString(nextPage) |
|||
nextPage = "" |
|||
For Each link In nextPageEx.Matches(page) |
|||
nextPage = basePage & link.Groups(1).Value |
|||
Next link |
|||
For Each language In languageStatEx.Matches(page) |
|||
Dim lCount As Integer = 0 |
|||
Dim lName As String = language.Groups(1).Value |
|||
Dim countText As String = language.Groups(2).Value.Replace(",", "").Replace(".", "") |
|||
If Not Integer.TryParse(countText, lCount) |
|||
Console.Out.WriteLine(lName & "Invalid page count: <<" & countText & ">>") |
|||
Else |
|||
languages.Add(New LanguageStat(lName, lCount)) |
|||
End If |
|||
Next language |
|||
Loop |
|||
languages.Sort(AddressOf CompareLanguages) |
|||
Dim prevCount As Integer = -1 |
|||
Dim prevPosition As Integer = -1 |
|||
Dim position As Integer = 0 |
|||
For Each stat As LanguageStat In languages |
|||
position += 1 |
|||
If stat.count <> prevCount Then |
|||
prevPosition = position |
|||
prevCount = stat.Count |
|||
End If |
|||
Console.Out.WriteLine(prevPosition.ToString.PadLeft(4) & ": " & |
|||
stat.count.ToString.PadLeft(4) & " " & stat.name) |
|||
Next stat |
|||
End Sub |
|||
End Module |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
Sample output as at 11th September 2023 |
|||
<pre> |
|||
1: 1652 Phix |
|||
1: 1652 Wren |
|||
3: 1614 Julia |
|||
4: 1595 Raku |
|||
5: 1576 Nim |
|||
6: 1546 Go |
|||
7: 1531 Perl |
|||
8: 1470 Python |
|||
9: 1375 J |
|||
10: 1285 C |
|||
. . . |
|||
</pre> |
|||
=={{header|Wren}}== |
|||
{{libheader|libcurl}} |
|||
{{libheader|Wren-pattern}} |
|||
{{libheader|Wren-fmt}} |
|||
An embedded program so we can use libcurl. |
|||
<syntaxhighlight lang="wren">/* Rosetta_Code_Rank_languages_by_popularity.wren */ |
|||
import "./pattern" for Pattern |
|||
import "./fmt" for Fmt |
|||
var CURLOPT_URL = 10002 |
|||
var CURLOPT_FOLLOWLOCATION = 52 |
|||
var CURLOPT_WRITEFUNCTION = 20011 |
|||
var CURLOPT_WRITEDATA = 10001 |
|||
foreign class Buffer { |
|||
construct new() {} // C will allocate buffer of a suitable size |
|||
foreign value // returns buffer contents as a string |
|||
} |
|||
foreign class Curl { |
|||
construct easyInit() {} |
|||
foreign easySetOpt(opt, param) |
|||
foreign easyPerform() |
|||
foreign easyCleanup() |
|||
} |
|||
var curl = Curl.easyInit() |
|||
var getContent = Fn.new { |url| |
|||
var buffer = Buffer.new() |
|||
curl.easySetOpt(CURLOPT_URL, url) |
|||
curl.easySetOpt(CURLOPT_FOLLOWLOCATION, 1) |
|||
curl.easySetOpt(CURLOPT_WRITEFUNCTION, 0) // write function to be supplied by C |
|||
curl.easySetOpt(CURLOPT_WRITEDATA, buffer) |
|||
curl.easyPerform() |
|||
return buffer.value |
|||
} |
|||
var p1 = Pattern.new("> <a href/=\"//wiki//Category:+1^\"\" title/=\"Category:[+1^\"]\">+1^,, [+1^ ] page") |
|||
var p2 = Pattern.new("subcatfrom/=[+1^#/#mw-subcategories]\"") |
|||
var findLangs = Fn.new { |
|||
var url = "https://rosettacode.org/w/index.php?title=Category:Programming_Languages" |
|||
var subcatfrom = "" |
|||
var langs = [] |
|||
while (true) { |
|||
var content = getContent.call(url + subcatfrom) |
|||
var matches1 = p1.findAll(content) |
|||
for (m in matches1) { |
|||
var name = m.capsText[0] |
|||
var tasks = Num.fromString(m.capsText[1].replace(",", "")) |
|||
langs.add([name, tasks]) |
|||
} |
|||
var m2 = p2.find(content) |
|||
if (m2) subcatfrom = "&subcatfrom=%(m2.capsText[0])" else break |
|||
} |
|||
return langs |
|||
} |
|||
var langs = findLangs.call() |
|||
langs.sort { |a, b| a[1] > b[1] } |
|||
System.print("Languages with most examples as at 3 February, 2024:") |
|||
var rank = 0 |
|||
var lastScore = 0 |
|||
var lastRank = 0 |
|||
for (i in 0...langs.count) { |
|||
var pair = langs[i] |
|||
var eq = " " |
|||
rank = i + 1 |
|||
if (lastScore == pair[1]) { |
|||
eq = "=" |
|||
rank = lastRank |
|||
} else { |
|||
lastScore = pair[1] |
|||
lastRank = rank |
|||
} |
|||
Fmt.print("$-3d$s $-20s $,5d", rank, eq, pair[0], pair[1]) |
|||
}</syntaxhighlight> |
|||
<br> |
|||
We now embed this script in the following C program, build and run. |
|||
<syntaxhighlight lang="c">/* gcc Rosetta_Code_Rank_languages_by_popularity.c -o Rosetta_Code_Rank_languages_by_popularity -lcurl -lwren -lm */ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <curl/curl.h> |
|||
#include "wren.h" |
|||
struct MemoryStruct { |
|||
char *memory; |
|||
size_t size; |
|||
}; |
|||
/* C <=> Wren interface functions */ |
|||
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { |
|||
size_t realsize = size * nmemb; |
|||
struct MemoryStruct *mem = (struct MemoryStruct *)userp; |
|||
char *ptr = realloc(mem->memory, mem->size + realsize + 1); |
|||
if(!ptr) { |
|||
/* out of memory! */ |
|||
printf("not enough memory (realloc returned NULL)\n"); |
|||
return 0; |
|||
} |
|||
mem->memory = ptr; |
|||
memcpy(&(mem->memory[mem->size]), contents, realsize); |
|||
mem->size += realsize; |
|||
mem->memory[mem->size] = 0; |
|||
return realsize; |
|||
} |
|||
void C_bufferAllocate(WrenVM* vm) { |
|||
struct MemoryStruct *ms = (struct MemoryStruct *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct MemoryStruct)); |
|||
ms->memory = malloc(1); |
|||
ms->size = 0; |
|||
} |
|||
void C_bufferFinalize(void* data) { |
|||
struct MemoryStruct *ms = (struct MemoryStruct *)data; |
|||
free(ms->memory); |
|||
} |
|||
void C_curlAllocate(WrenVM* vm) { |
|||
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*)); |
|||
*pcurl = curl_easy_init(); |
|||
} |
|||
void C_value(WrenVM* vm) { |
|||
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 0); |
|||
wrenSetSlotString(vm, 0, ms->memory); |
|||
} |
|||
void C_easyPerform(WrenVM* vm) { |
|||
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0); |
|||
curl_easy_perform(curl); |
|||
} |
|||
void C_easyCleanup(WrenVM* vm) { |
|||
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0); |
|||
curl_easy_cleanup(curl); |
|||
} |
|||
void C_easySetOpt(WrenVM* vm) { |
|||
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0); |
|||
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1); |
|||
if (opt < 10000) { |
|||
long lparam = (long)wrenGetSlotDouble(vm, 2); |
|||
curl_easy_setopt(curl, opt, lparam); |
|||
} else if (opt < 20000) { |
|||
if (opt == CURLOPT_WRITEDATA) { |
|||
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 2); |
|||
curl_easy_setopt(curl, opt, (void *)ms); |
|||
} else if (opt == CURLOPT_URL) { |
|||
const char *url = wrenGetSlotString(vm, 2); |
|||
curl_easy_setopt(curl, opt, url); |
|||
} |
|||
} else if (opt < 30000) { |
|||
if (opt == CURLOPT_WRITEFUNCTION) { |
|||
curl_easy_setopt(curl, opt, &WriteMemoryCallback); |
|||
} |
|||
} |
|||
} |
|||
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) { |
|||
WrenForeignClassMethods methods; |
|||
methods.allocate = NULL; |
|||
methods.finalize = NULL; |
|||
if (strcmp(module, "main") == 0) { |
|||
if (strcmp(className, "Buffer") == 0) { |
|||
methods.allocate = C_bufferAllocate; |
|||
methods.finalize = C_bufferFinalize; |
|||
} else if (strcmp(className, "Curl") == 0) { |
|||
methods.allocate = C_curlAllocate; |
|||
} |
|||
} |
|||
return methods; |
|||
} |
|||
WrenForeignMethodFn bindForeignMethod( |
|||
WrenVM* vm, |
|||
const char* module, |
|||
const char* className, |
|||
bool isStatic, |
|||
const char* signature) { |
|||
if (strcmp(module, "main") == 0) { |
|||
if (strcmp(className, "Buffer") == 0) { |
|||
if (!isStatic && strcmp(signature, "value") == 0) return C_value; |
|||
} else if (strcmp(className, "Curl") == 0) { |
|||
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt; |
|||
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform; |
|||
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup; |
|||
} |
|||
} |
|||
return NULL; |
|||
} |
|||
static void writeFn(WrenVM* vm, const char* text) { |
|||
printf("%s", text); |
|||
} |
|||
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) { |
|||
switch (errorType) { |
|||
case WREN_ERROR_COMPILE: |
|||
printf("[%s line %d] [Error] %s\n", module, line, msg); |
|||
break; |
|||
case WREN_ERROR_STACK_TRACE: |
|||
printf("[%s line %d] in %s\n", module, line, msg); |
|||
break; |
|||
case WREN_ERROR_RUNTIME: |
|||
printf("[Runtime Error] %s\n", msg); |
|||
break; |
|||
} |
|||
} |
|||
char *readFile(const char *fileName) { |
|||
FILE *f = fopen(fileName, "r"); |
|||
fseek(f, 0, SEEK_END); |
|||
long fsize = ftell(f); |
|||
rewind(f); |
|||
char *script = malloc(fsize + 1); |
|||
fread(script, 1, fsize, f); |
|||
fclose(f); |
|||
script[fsize] = 0; |
|||
return script; |
|||
} |
|||
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) { |
|||
if( result.source) free((void*)result.source); |
|||
} |
|||
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) { |
|||
WrenLoadModuleResult result = {0}; |
|||
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) { |
|||
result.onComplete = loadModuleComplete; |
|||
char fullName[strlen(name) + 6]; |
|||
strcpy(fullName, name); |
|||
strcat(fullName, ".wren"); |
|||
result.source = readFile(fullName); |
|||
} |
|||
return result; |
|||
} |
|||
int main(int argc, char **argv) { |
|||
WrenConfiguration config; |
|||
wrenInitConfiguration(&config); |
|||
config.writeFn = &writeFn; |
|||
config.errorFn = &errorFn; |
|||
config.bindForeignClassFn = &bindForeignClass; |
|||
config.bindForeignMethodFn = &bindForeignMethod; |
|||
config.loadModuleFn = &loadModule; |
|||
WrenVM* vm = wrenNewVM(&config); |
|||
const char* module = "main"; |
|||
const char* fileName = "Rosetta_Code_Rank_languages_by_popularity.wren"; |
|||
char *script = readFile(fileName); |
|||
WrenInterpretResult result = wrenInterpret(vm, module, script); |
|||
switch (result) { |
|||
case WREN_RESULT_COMPILE_ERROR: |
|||
printf("Compile Error!\n"); |
|||
break; |
|||
case WREN_RESULT_RUNTIME_ERROR: |
|||
printf("Runtime Error!\n"); |
|||
break; |
|||
case WREN_RESULT_SUCCESS: |
|||
break; |
|||
} |
|||
wrenFreeVM(vm); |
|||
free(script); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
Showing just the top thirty. |
|||
<pre> |
|||
Languages with most examples as at 3 February, 2024: |
|||
1 Wren 1,665 |
|||
1 = Phix 1,665 |
|||
3 Julia 1,638 |
|||
4 Raku 1,608 |
|||
5 Nim 1,576 |
|||
6 Go 1,547 |
|||
7 Perl 1,540 |
|||
8 Python 1,497 |
|||
9 J 1,413 |
|||
10 Java 1,318 |
|||
11 C 1,293 |
|||
12 C++ 1,258 |
|||
13 Ruby 1,235 |
|||
14 Mathematica 1,200 |
|||
15 FreeBASIC 1,185 |
|||
16 Haskell 1,166 |
|||
17 REXX 1,152 |
|||
18 Kotlin 1,143 |
|||
19 Racket 1,099 |
|||
20 Jq 1,081 |
|||
21 Sidef 1,051 |
|||
22 11l 1,016 |
|||
23 Zkl 1,011 |
|||
24 Factor 1,001 |
|||
25 D 990 |
|||
26 ALGOL 68 986 |
|||
27 Tcl 983 |
|||
28 Scala 948 |
|||
29 Delphi 945 |
|||
30 Ada 940 |
|||
30 = Rust 940 |
|||
</pre> |
|||
=={{header|zkl}}== |
|||
Using cURL and YAJL (yet anothe JSON library) libraries. |
|||
This solution using the API as the web scraping URL is pretty slow. |
|||
I'm using JSON as format=txt has been deprecated. |
|||
<syntaxhighlight lang="zkl">var [const] CURL=Import("zklCurl"), YAJL=Import("zklYAJL")[0]; |
|||
fcn getLangCounts(language){ // -->( (count,lang), ...) |
|||
continueValue,tasks,curl := "",List(), CURL(); // "nm\0nm\0...." |
|||
do{ // eg 5 times |
|||
page:=curl.get(("http://rosettacode.org/mw/api.php?" |
|||
"format=json" |
|||
"&action=query" |
|||
"&generator=categorymembers" |
|||
"&gcmtitle=Category:Programming%%20Languages" |
|||
"&gcmlimit=500" |
|||
"&prop=categoryinfo" |
|||
"&rawcontinue" // remove warning |
|||
"&gcmcontinue=%s") |
|||
.fmt(continueValue)); |
|||
page=page[0].del(0,page[1]); // get rid of HTML header |
|||
json:=YAJL().write(page).close(); |
|||
json["query"]["pages"].howza(9).pump(tasks,fcn(d){ #dictionary values,only |
|||
// { title:Category:AWK,categoryinfo:{ pages:398,size:401,... },... } |
|||
// Gotta take care of no categoryinfo case |
|||
count:=d.find("categoryinfo",Dictionary).find("size",0); // or pages? |
|||
if(count<300) return(Void.Skip); // prune |
|||
T(count,d["title"].del(0,9)); // "Category:RPL" --> "RPL" |
|||
}); |
|||
if(continueValue=json.find("query-continue")) |
|||
// subcat|524558580a52455858|4331 or void |
|||
continueValue=continueValue["categorymembers"]["gcmcontinue"]; |
|||
}while(continueValue); |
|||
tasks |
|||
} |
|||
langCounts:=getLangCounts() .sort(fcn(a,b){ a[0]>b[0] }); // reverse sort |
|||
println("Most popular Rosetta Code languages as of ",Time.Date.prettyDay()); |
|||
foreach n,name in ([1..15].zip(langCounts)) |
|||
{ println("%2d: %3d %s".fmt(n,name.xplode())) }</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Most popular Rosetta Code languages as of Saturday, the 23rd of September 2017 |
|||
1: 957 Racket |
|||
2: 953 Python |
|||
3: 918 Tcl |
|||
4: 904 Perl 6 |
|||
5: 877 J |
|||
6: 854 Zkl |
|||
7: 840 Ruby |
|||
8: 828 C |
|||
9: 812 Go |
|||
10: 805 Haskell |
|||
11: 801 REXX |
|||
12: 800 Kotlin |
|||
13: 788 Java |
|||
14: 776 Perl |
|||
15: 755 D |
|||
</pre> |
|||
{{omit from|Batch File}} |
|||
{{omit from|Brainf***}} |
|||
{{omit from|Lilypond}} |
|||
{{omit from|Maxima}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|PostScript}} |
|||
{{omit from|TI-83 BASIC|Does not have network access.}} |
|||
{{omit from|TI-89 BASIC|Does not have network access.}} |
|||
{{omit from|Yorick|Does not have network access.}} |
|||
{{omit from|ZX Spectrum Basic|Does not have network access.}} |
Latest revision as of 15:37, 3 June 2024
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
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 02 August 2022 at 09:50 +02
Rank: 1 (1,565 entries) Phix Rank: 2 (1,558 entries) Wren Rank: 3 (1,531 entries) Julia Rank: 4 (1,507 entries) Raku Rank: 5 (1,500 entries) Go Rank: 6 (1,466 entries) Perl Rank: 7 (1,409 entries) Python Rank: 8 (1,402 entries) Nim Rank: 9 (1,254 entries) J Rank: 10 (1,211 entries) C ...
- Notes
- Each language typically demonstrates one or two methods of accessing the data:
- with web scraping (via http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000)
- with the API method (examples below for Awk, Perl, Ruby, Tcl, etc).
- 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 950 programming languages, updated periodically, typically weekly.
- A complete ranked listing of all 813 languages (from the REXX example) is included here ──► output from the REXX program.
Ada
Ada 2022: using web scraping
pragma Ada_2022;
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.Unbounded.Less_Case_Insensitive;
with Ada.Characters.Handling; use Ada.Characters.Handling;
with AWS.Client; use AWS.Client;
with AWS.Messages; use AWS.Messages;
with AWS.Response;
procedure Rank_Languages_By_Popularity is
use Ada.Strings;
function "+" (S : String) return Unbounded_String
renames To_Unbounded_String;
type A_Language_Count is
record
Count : Natural := 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 => L.Language,
Right => R.Language));
end "<";
package Sets is new Ada.Containers.Ordered_Sets (A_Language_Count);
use Sets;
Counts : Set;
procedure Find_Counts (S : String) is
function Strip_Character (S : String; C : Character) return String is
S_Copy_Str : String (1 .. S'Length);
S_Copy_Index : Natural := 0;
begin
for I in S'Range loop
if S (I) /= C then
S_Copy_Index := S_Copy_Index + 1;
S_Copy_Str (S_Copy_Index) := S (I);
end if;
end loop;
return S_Copy_Str (S_Copy_Str'First .. S_Copy_Index);
end Strip_Character;
function Ignore_Category (L : String) return Boolean is
type Unbounded_String_Array is array (Positive range <>)
of Unbounded_String;
-- This list is quite comprehensive, but not complete
Categories_To_Ignore : Unbounded_String_Array := [
+"Pages with syntax highlighting errors",
+"Programming",
+"Examples needing attention",
+"Tasks needing attention",
+"Language users",
+"Implementations",
+"Solutions by ",
+"Maintenance/OmitCategoriesCreated",
+"Collection Members",
+"Pages with too many expensive parser function calls",
+"Garbage collection",
+" User",
+"SQL User",
+"Typing",
+"Parameter passing",
+"Execution method",
+"Unimplemented tasks by language",
+"Wolfram Language",
+"/Omit",
+"Wren-",
+"WrenGo",
+"Phix/",
+"PhixClass",
+"Basic language learning",
+"Encyclopedia",
+"RCTemplates",
+"SysUtils",
+"Action! ",
+"Text processing",
+"Image processing",
+"Scala Digital Signal Processing",
+"List processing",
+"Digital signal processing",
+"Processing Python",
+"Classic CS problems and programs",
+"Brainf*** related",
+"Data Structures",
+"Perl modules",
+"Perl/",
+"Perl:LWP",
+"Perl 6 related",
+"Flow control",
+"Excessively difficult task",
+"WikiStubs",
+"Impl needed",
+"Recursion"
];
begin
for Category of Categories_To_Ignore loop
declare
Category_At : constant Natural :=
Index (+To_Lower (L),
To_Lower (To_String (Category)));
begin
if Category_At /= 0 then
return True;
end if;
end;
end loop;
return False;
end Ignore_Category;
Title_Str : constant String := "title=""Category:";
End_A_Tag_Str : constant String := "</a>";
Space_Paren_Str : constant String := " (";
Title_At : constant Natural := Index (S, Title_Str);
begin
if Title_At /= 0 then
declare
Closing_Bracket_At : constant Natural :=
Index (S (Title_At + Title_Str'Length .. S'Last), ">");
End_A_Tag_At : constant Natural :=
Index (S (Closing_Bracket_At + 1 .. S'Last), End_A_Tag_Str);
Language : constant String :=
S (Closing_Bracket_At + 1 .. End_A_Tag_At - 1);
Space_Paren_At : constant Natural :=
Index (S (End_A_Tag_At + 1 .. S'Last), Space_Paren_Str);
Space_At : constant Natural :=
Index (S (Space_Paren_At + Space_Paren_Str'Length + 1
.. S'Last),
" ");
Count : constant Natural :=
Natural'Value (
Strip_Character (
S (Space_Paren_At +
Space_Paren_Str'Length
.. Space_At - 1),
','));
begin
if Closing_Bracket_At /= 0
and then End_A_Tag_At /= 0
and then Space_Paren_At /= 0
and then Space_At /= 0
then
begin
if Ignore_Category (Language) = False then
Counts.Insert (New_Item => (Count, +Language));
end if;
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/w/index.php?" &
"title=Special:Categories&limit=5000",
Follow_Redirection => True);
Status : Status_Code;
begin
Put_Line ("Getting website data...");
Status := AWS.Response.Status_Code (Http_Source);
if Status not in Success then
Put_Line ("Unable to retrieve data => Status Code :" &
Image (Status) &
" Reason :" & Reason_Phrase (Status));
raise Connection_Error;
end if;
Put_Line ("Finding categories...");
Find_Counts (AWS.Response.Message_Body (Http_Source));
Put_Line ("Displaying categories...");
Counts.Reverse_Iterate (Display'Access);
Put_Line ("Process complete.");
end Rank_Languages_By_Popularity;
- Sample output:
1. 1683 - Phix 2. 1676 - Wren 3. 1653 - Julia 4. 1623 - Raku 5. 1577 - Nim 6. 1553 - Go 7. 1548 - Perl 8. 1532 - Python 9. 1416 - J 10. 1349 - Java 11. 1333 - FreeBASIC 12. 1300 - C 13. 1282 - C++ 14. 1239 - Ruby 15. 1209 - Mathematica 16. 1175 - Haskell 17. 1156 - REXX 18. 1152 - Kotlin 19. 1149 - Jq 20. 1102 - Racket 21. 1055 - Sidef 22. 1021 - ALGOL 68 23. 1017 - 11l 24. 1012 - Zkl 25. 1004 - Factor 26. 993 - D 27. 989 - C sharp 28. 987 - Tcl 29. 973 - Scala 30. 959 - Ada 31. 954 - Rust 32. 949 - Delphi 33. 947 - Lua 34. 868 - F Sharp 35. 867 - XPL0
ALGOL 68
ALGOL68: using web scraping
Note: the routine http content is currently not available on Win32 systems.
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
);
# 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
- 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
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";
# concatenate tuples #
OP + = ([]STRING a, b) []STRING:
BEGIN
[⌈a + ⌈b] STRING c;
c[:⌈a] := a;
c[⌈a+1:] := b;
c
END;
# 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;
# 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;
# 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;
# 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;
# 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;
# the main program rank languages by popularity starts here #
STRING gcmcontinue;
FLEX[0]STRING lines;
# 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;
# 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
- 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
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:([^""]+)"">(?=.*</table>)"
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
AWK
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").
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]
}
- 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.
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
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
( 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
)
)
& ;
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
Ghetto parser
#include <stdio.h>
#include <stdlib.h>
#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";
#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;
}
- Output:
563 Tcl 529 PicoLisp 522 Python 504 C 500 J 442 Go 440 Ruby 435 Ada 430 PureBasic 427 Perl ...
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.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#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);
}
- 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.
Note that this does not distinguish between tasks and non-task categories, so the counts can exceed the total number of tasks.
Note this may need to set the Security Protocol type to Tls12 - see the section Problem running the C# entry in Talk:Rosetta_Code/Count_examples
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 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>();
string cmcontinue = "";
do
{
string get1 = new WebClient().DownloadString("http://www.rosettacode.org/w/api.php?"
+"action=query&list=categorymembers"
+"&cmtitle=Category:Programming_Languages"
+"&cmlimit=500&format=json"
+cmcontinue
);
cmcontinue = "";
MatchCollection languageMatch = new Regex("\"title\":\"Category:(.+?)\"").Matches(get1);
MatchCollection cmcontinueMatch = new Regex("cmcontinue\":\"([a-z0-9A-Z|]*)\"").Matches(get1);
foreach (Match lang in languageMatch) langs.Add(lang.Groups[1].Value);
foreach (Match more in cmcontinueMatch) cmcontinue = "&cmcontinue=" + more.Groups[1].Value;
}
while( cmcontinue != "" );
MatchCollection match2 =
new Regex("title=\"Category:(.+?)\">.+?</a>[^(]*\\(([\\d,.]+) members\\)").Matches(get2);
foreach (Match match in match2)
{
if (langs.Contains(match.Groups[1].Value))
{
qtdmbr.Add(match.Groups[1].Value, Int32.Parse(match.Groups[2].Value
.Replace(",",string.Empty)
.Replace(".",string.Empty)));
}
}
string[] test =
qtdmbr.OrderByDescending(x => x.Value).Select(x => String.Format("{0,4} {1}", x.Value, x.Key)).ToArray();
int count = 1;
foreach (string i in test)
{
Console.WriteLine("{0,4}: {1}", count, i);
count++;
}
}
}
- Output (as of September 11, 2023):
1: 1660 Phix 2: 1653 Wren 3: 1617 Julia 4: 1598 Raku 5: 1577 Nim 6: 1548 Go 7: 1537 Perl 8: 1487 Python 9: 1376 J 10: 1287 C . . .
Object-oriented solution
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++;
}
}
}
C++
using g++ under Linux with g++ -lboost_thread -lboost_system -lboost_regex:
#include <string>
#include <boost/regex.hpp>
#include <boost/asio.hpp>
#include <vector>
#include <utility>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#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( "<li><a href=\"[^<>]+?\">([a-zA-Z\\+#1-9]+?)</a>\\s?\\((\\d+) members\\)</li>" ) ;
//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 ;
}
- 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
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
}
}
- 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".
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[]);
}
- 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
For safe run, download dlls: libeay32.dll & ssleay32.dll, then put in executable path.
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.
- 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
-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}.
- 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#
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
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
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("<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})
}
}
}
// 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)
}
}
- 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
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 =~ '<li><a[^>]+>([^<]+)</a>[^(]*[(](\\d+) member[s]*[)]</li>').each { match, language, members ->
count[language] = (members as int)
}
count.sort { v1, v2 -> v2.value <=> v1.value }.eachWithIndex { value, index -> println "${index + 1} $value" }
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
{-# 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
- 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.
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 "<li>") $ 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
- 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
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) THEN
nr = nr + 1
WRITE(Text=catlist, Format='i4, 1x, 2a', APPend) count, name, ';'
ENDIF
GOTO 1 ! no WHILE in HicEst
ENDIF ! catlist is now = " 1 ... User ; 2 100 doors ; 3 3D ; 8 4D ; ..."
ALLOCATE(RankNr, nr)
EDIT(Text=catlist, SePaRators=';', Option=1+4, SorTtoIndex=RankNr) ! case (1) and back (4)
sortedCat = ' ' ! get the sorted list in the sequence of RankNr:
ok = 0
DO i = 1, nr
EDIT(Text=catlist, SePaRators=';', ITeM=RankNr(i), CoPyto=sample)
discard = EDIT(Text=sample, LeXicon='user,attention,solutions,tasks,program,language,implementation,')
IF(discard == 0) THEN ! removes many of the non-language entries
ok = ok + 1
WRITE(Text=sortedCat, APPend, Format='F5.0, 2A') ok, TRIM(sample), $CRLF
ENDIF
ENDDO
DLG(Text=sortedCat, Format=$CRLF)
END
2010-04-24 18:31
Top 10 entries (not all are languages)
1. 394 Tcl
2. 363 Python
3. 346 Ruby
4. 328 J
5. 319 C
6. 317 OCaml
7. 315 Haskell
8. 298 Perl
9. 288 WikiStubs
10. 281 Common Lisp
Icon and Unicon
By using the API
The following solution only works in Unicon.
$define RCLANGS "http://rosettacode.org/mw/api.php?format=xml&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo"
$define RCUA "User-Agent: Unicon Rosetta 0.1"
$define RCXUA "X-Unicon: http://unicon.org/"
link strings
link hexcvt
procedure main()
cnt := create seq()
last := -1
every pair := !reverse(sort(langs := tallyPages(),2)) do {
n := if last ~=:= pair[2] then @cnt else (@cnt,"")
write(right(n,4),": ",left(pair[1],30,". "),right(pair[2],10,". "))
}
write(*langs, " languages")
end
# Generate page counts for each language
procedure tallyPages(url)
/url := RCLANGS
counts := table()
continue := ""
while \(txt := ReadURL(url||continue)) do {
txt ? {
if tab(find("gcmcontinue=")) then {
continue := "&"||tab(upto('"'))
move(1)
continue ||:= tab(upto('"'))
}
else continue := ""
while tab(find("<page ") & find(s := "title=\"Category:")+*s) do {
lang := tab(upto('"'))
tab(find(s := "pages=\"")+*s)
counts[lang] := numeric(tab(upto('"')))
}
if continue == "" then return counts
}
}
end
procedure ReadURL(url) #: read URL into string
page := open(url,"m",RCUA,RCXUA) | stop("Unable to open ",url)
text := ""
if page["Status-Code"] < 300 then while text ||:= reads(page,-1)
else write(&errout,image(url),": ",
page["Status-Code"]," ",page["Reason-Phrase"])
close(page)
return text
end
Abridged output (top 26 languages as of July 30, 2016):
1: Racket. . . . . . . . . . . . . . . .904 2: Tcl . . . . . . . . . . . . . . . . .894 3: Python. . . . . . . . . . . . . . . .867 4: J . . . . . . . . . . . . . . . . . .852 5: Perl 6. . . . . . . . . . . . . . . .824 6: Ruby. . . . . . . . . . . . . . . . .796 7: C . . . . . . . . . . . . . . . . . .777 8: Go. . . . . . . . . . . . . . . . . .769 9: Java. . . . . . . . . . . . . . . . .764 10: D . . . . . . . . . . . . . . . . . .747 11: REXX. . . . . . . . . . . . . . . . .743 12: Perl. . . . . . . . . . . . . . . . .736 13: Haskell . . . . . . . . . . . . . . .712 : Zkl . . . . . . . . . . . . . . . . .712 15: PicoLisp. . . . . . . . . . . . . . .695 16: Mathematica . . . . . . . . . . . . .686 17: Sidef . . . . . . . . . . . . . . . .632 18: Ada . . . . . . . . . . . . . . . . .626 19: C++ . . . . . . . . . . . . . . . . .619 20: AutoHotkey. . . . . . . . . . . . . .603 21: Unicon. . . . . . . . . . . . . . . .578 22: Common Lisp . . . . . . . . . . . . .577 23: Scala . . . . . . . . . . . . . . . .561 24: BBC BASIC . . . . . . . . . . . . . .535 25: C sharp . . . . . . . . . . . . . . .529 26: Icon. . . . . . . . . . . . . . . . .520 ... 604 languages
J
Solution:
require 'web/gethttp xml/sax/x2j regex'
x2jclass 'rcPopLang'
rx =: (<0 1) {:: (2#a:) ,~ rxmatches rxfrom ]
'Popular Languages' x2jDefn
/ := langs : langs =: 0 2 $ a:
html/body/div/div/div/ul/li := langs =: langs ,^:(a:~:{.@[)~ lang ; ' \((\d+) members?\)' rx y
html/body/div/div/div/ul/li/a := lang =: '^\s*((?:.(?!User|Tasks|Omit|attention|operations|by))+)\s*$' rx y
)
cocurrent'base'
sortTab =. \: __ ". [: ;:^:_1: {:"1
formatTab =: [: ;:^:_1: [: (20 A. (<'-') , |. , [: ('.' <"1@:,.~ ":) 1 + 1 i.@,~ 1{$)&.|: sortTab f.
rcPopLangs =: formatTab@:process_rcPopLang_@:gethttp
Example:
10 {. rcPopLangs 'http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=2000'
1. 687 - Tcl
2. 646 - Python
3. 637 - C
4. 626 - PicoLisp
5. 612 - J
6. 587 - Go
7. 556 - Ada
8. 550 - D
9. 549 - Mathematica
10. 526 - Perl
Notes: See some notes on the J solution.
Java
Tested with Java 1.22. Uses the api.
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.io.*;
import java.util.*;
public class GetRCLanguages
{
// Custom sort Comparator for sorting the language list
// assumes the first character is the page count and the rest is the language name
private static class LanguageComparator implements Comparator<String>
{
public int compare( String a, String b )
{
// as we "know" we will be comparaing languages, we will assume the Strings have the appropriate format
int result = ( b.charAt( 0 ) - a.charAt( 0 ) );
if( result == 0 )
{
// the counts are the same - compare the names
result = a.compareTo( b );
} // if result == 0
return result;
} // compare
} // LanguageComparator
// get the string following marker in text
private static String after( String text, int marker )
{
String result = "";
int pos = text.indexOf( marker );
if( pos >= 0 )
{
// the marker is in the string
result = text.substring( pos + 1 );
} // if pos >= 0
return result;
} // after
// read and parse the content of path
// results returned in gcmcontinue and languageList
public static void parseContent( String path
, String[] gcmcontinue
, ArrayList<String> languageList
)
{
try
{
URL url = new URI( path ).toURL();
URLConnection rc = url.openConnection();
BufferedReader bfr = new BufferedReader( new InputStreamReader( rc.getInputStream() ) );
gcmcontinue[0] = "";
String languageName = "?";
String line = bfr.readLine();
while( line != null )
{
line = line.trim().replaceAll( "[\",]", "" );
if ( line.startsWith( "title" ) )
{
// have a programming language - should look like "title: Category:languageName"
languageName = after( after( line, ':' ), ':' ).trim();
}
else if( line.startsWith( "pages" ) )
{
// number of pages the language has (probably)
String pageCount = after( line, ':' ).trim();
if( pageCount.compareTo( "{" ) != 0 )
{
// haven't got "pages: {" - must be a number of pages
languageList.add( ( (char) Integer.parseInt( pageCount ) ) + languageName );
languageName = "?";
} // if [pageCount.compareTo( "{" ) != 0
}
else if( line.startsWith( "gcmcontinue" ) )
{
// have an indication of wether there is more data or not
gcmcontinue[0] = after( line, ':' ).trim().replaceAll( "[|]", "%7C" );
} // if various line starts
line = bfr.readLine();
} // while line != null
bfr.close();
}
catch( Exception e )
{
e.printStackTrace();
} // try-catch
} // parseContent
public static void main( String[] args )
{
// get the languages
ArrayList<String> languageList = new ArrayList<String>( 1000 );
String[] gcmcontinue = new String[1];
gcmcontinue[0] = "";
do
{
String path = ( "https://www.rosettacode.org/w/api.php?action=query"
+ "&generator=categorymembers"
+ "&gcmtitle=Category:Programming%20Languages"
+ "&gcmlimit=500"
+ ( gcmcontinue[0].compareTo( "" ) == 0 ? "" : ( "&gcmcontinue=" + gcmcontinue[0] ) )
+ "&prop=categoryinfo"
+ "&format=jsonfm"
);
parseContent( path, gcmcontinue, languageList );
}
while( gcmcontinue[0].compareTo( "" ) != 0 );
// sort the languages
String[] languages = languageList.toArray(new String[]{});
Arrays.sort( languages, new LanguageComparator() );
// print the languages
int lastTie = -1;
int lastCount = -1;
for( int lPos = 0; lPos < languages.length; lPos ++ )
{
int count = (int) ( languages[ lPos ].charAt( 0 ) );
System.out.format( "%4d: %4d: %s\n"
, 1 + ( count == lastCount ? lastTie : lPos )
, count
, languages[ lPos ].substring( 1 )
);
if( count != lastCount )
{
lastTie = lPos;
lastCount = count;
} // if count != lastCount
} // for lPos
} // main
} // GetRCLanguages
- Output:
Top 10 languages as at 1st June 2024
1: 1675: Phix 1: 1675: Wren 3: 1650: Julia 4: 1620: Raku 5: 1576: Nim 6: 1549: Go 7: 1542: Perl 8: 1514: Python 9: 1413: J 10: 1346: Java ...
jq
The following solution matches the languages listed on the Category:Programming_Languages page with the statistics given on the Special:Categories page, making an adjustment for the number of irrelevant subcategories.
jq 1.4 cannot retrieve documents over the web and has no support for regular expressions, but is intended to work seamlessly with other command line tools, so the following solution is presented in the form of a bash script that uses curl for retrieval, and grep and sed for screen scraping.
#!/bin/bash
# produce lines of the form: [ "language", n ]
function categories {
curl -Ss 'http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000' |\
grep "/wiki/Category:" | grep member | grep -v '(.*(' |\
grep -v ' User</a>' |\
sed -e 's/.*title="Category://' -e 's/member.*//' |\
sed 's:^\([^"]*\)"[^(]*(\(.*\):["\1", \2]:'
}
# produce lines of the form: "language"
function languages {
curl -Ss 'http://rosettacode.org/wiki/Category:Programming_Languages' |\
sed '/Pages in category "Programming Languages"/,$d' |\
grep '<li><a href="/wiki/Category:' | fgrep title= |\
sed 's/.*Category:\([^"]*\)".*/"\1"/'
}
categories |\
/usr/local/bin/jq --argfile languages <(languages) -s -r '
# input: array of [score, _] sorted by score
# output: array of [ranking, score, _]
def ranking:
reduce .[] as $x
([]; # array of [count, rank, score, _]
if length == 0 then [[1, 1] + $x]
else .[length - 1] as $previous
| if $x[0] == $previous[2]
then . + [ [$previous[0] + 1, $previous[1]] + $x ]
else . + [ [$previous[0] + 1, $previous[0] + 1] + $x ]
end
end)
| [ .[] | .[1:] ];
# Every language page has three category pages that should be excluded
(reduce .[] as $pair
({};
($pair[1] as $n | if $n > 3 then . + {($pair[0]): ($n - 3)} else . end ))) as $freq
| [ $languages[] | select($freq[.] != null) | [$freq[.], .]]
| sort
| reverse
| ranking[]
| "\(.[0]). \(.[1]) - \(.[2])" '
- Output:
# First ten and last ten lines as of May 27, 2015
$ pop.sh
1. 868 - Tcl
2. 863 - Racket
3. 842 - Python
4. 778 - J
5. 769 - Ruby
6. 756 - Perl 6
7. 752 - C
8. 736 - D
9. 735 - Go
10. 700 - Perl
...
386. 1 - FP
386. 1 - ElastiC
386. 1 - ESQL
386. 1 - Clipper/XBase++
386. 1 - Bori
386. 1 - Biferno
386. 1 - AspectJ
386. 1 - Algae
386. 1 - 80386 Assembly
386. 1 - 68000 Assembly
Julia
Uses the API for the language list and page scraping for the example counts for each language.
""" Rosetta code task rosettacode.org/wiki/Rosetta_Code/Rank_languages_by_popularity """
using Dates
using DataFrames
using HTTP
using JSON3
""" Get listing of all tasks and draft tasks with authors and dates created, with the counts as popularity """
function rosetta_code_language_example_counts(verbose = false)
URL = "https://rosettacode.org/w/api.php?"
LANGPARAMS = ["action" => "query", "format" => "json", "formatversion" => "2", "generator" => "categorymembers",
"gcmtitle" => "Category:Programming_Languages", "gcmlimit" => "500", "rawcontinue" => "", "prop" => "title"]
queryparams = copy(LANGPARAMS)
df = empty!(DataFrame([[""], [0]], ["ProgrammingLanguage", "ExampleCount"]))
while true # get all the languages listed, with curid, eg rosettacode.org/w/index.php?curid=196 for C
resp = HTTP.get(URL * join(map(p -> p[1] * (p[2] == "" ? "" : ("=" * p[2])), queryparams), "&"))
json = JSON3.read(String(resp.body))
pages = json.query.pages
reg = r"The following \d+ pages are in this category, out of ([\d\,]+) total"
for p in pages
lang = replace(p.title, "Category:" => "")
langpage = String(HTTP.get("https://rosettacode.org/w/index.php?curid=" * string(p.pageid)).body)
if !((m = match(reg, langpage)) isa Nothing)
push!(df, [lang, parse(Int, replace(m.captures[1], "," => ""))])
verbose && println("Language: $lang, count: ", m.captures[1])
end
end
!haskey(json, "query-continue") && break # break if no more pages, else continue to next pages
queryparams = vcat(LANGPARAMS, "gcmcontinue" => json["query-continue"]["categorymembers"]["gcmcontinue"])
end
return sort!(df, :ExampleCount, rev = true)
end
println("Top 20 Programming Languages on Rosetta Code by Number of Examples, As of: ", now())
println(rosetta_code_language_example_counts()[begin:begin+19, :])
- Output:
Top 20 Programming Languages on Rosetta Code by Number of Examples, As of: 2022-09-05T14:59:56.316 20×2 DataFrame Row │ ProgrammingLanguage ExampleCount │ String Int64 ─────┼─────────────────────────────────── 1 │ Wren 1569 2 │ Phix 1569 3 │ Julia 1537 4 │ Raku 1517 5 │ Go 1496 6 │ Perl 1460 7 │ Python 1404 8 │ Nim 1402 9 │ J 1275 10 │ C 1210 11 │ Mathematica 1178 12 │ REXX 1149 13 │ Haskell 1139 14 │ Java 1136 15 │ Kotlin 1133 16 │ C++ 1120 17 │ Ruby 1103 18 │ Racket 1089 19 │ FreeBASIC 1069 20 │ Zkl 1011
Kotlin
import java.net.URL
import java.io.*
object Popularity {
/** Gets language data. */
fun ofLanguages(): List<String> {
val languages = mutableListOf<String>()
var gcm = ""
do {
val path = url + (if (gcm == "") "" else "&gcmcontinue=" + gcm) + "&prop=categoryinfo" + "&format=txt"
try {
val rc = URL(path).openConnection() // URL completed, connection opened
// Rosetta Code objects to the default Java user agent so use a blank one
rc.setRequestProperty("User-Agent", "")
val bfr = BufferedReader(InputStreamReader(rc.inputStream))
try {
gcm = ""
var languageName = "?"
var line: String? = bfr.readLine()
while (line != null) {
line = line.trim { it <= ' ' }
if (line.startsWith("[title]")) {
// have a programming language - should look like "[title] => Category:languageName"
languageName = line[':']
} else if (line.startsWith("[pages]")) {
// number of pages the language has (probably)
val pageCount = line['>']
if (pageCount != "Array") {
// haven't got "[pages] => Array" - must be a number of pages
languages += pageCount.toInt().toChar() + languageName
languageName = "?"
}
} else if (line.startsWith("[gcmcontinue]"))
gcm = line['>'] // have an indication of whether there is more data or not
line = bfr.readLine()
}
} finally {
bfr.close()
}
} catch (e: Exception) {
e.printStackTrace()
}
} while (gcm != "")
return languages.sortedWith(LanguageComparator)
}
/** Custom sort Comparator for sorting the language list.
* Assumes the first character is the page count and the rest is the language name. */
internal object LanguageComparator : java.util.Comparator<String> {
override fun compare(a: String, b: String): Int {
// as we "know" we will be comparing languages, we will assume the Strings have the appropriate format
var r = b.first() - a.first()
return if (r == 0) a.compareTo(b) else r
// r == 0: the counts are the same - compare the names
}
}
/** Gets the string following marker in text. */
private operator fun String.get(c: Char) = substringAfter(c).trim { it <= ' ' }
private val url = "http://www.rosettacode.org/mw/api.php?action=query" +
"&generator=categorymembers" + "&gcmtitle=Category:Programming%20Languages" +
"&gcmlimit=500"
}
fun main(args: Array<String>) {
// read/sort/print the languages (CSV format):
var lastTie = -1
var lastCount = -1
Popularity.ofLanguages().forEachIndexed { i, lang ->
val count = lang.first().toInt()
if (count == lastCount)
println("%12s%s".format("", lang.substring(1)))
else {
println("%4d, %4d, %s".format(1 + if (count == lastCount) lastTie else i, count, lang.substring(1)))
lastTie = i
lastCount = count
}
}
}
- Output:
1, 901, Racket 2, 893, Tcl 3, 851, Python 4, 826, J 5, 796, Perl 6 ... 135, 70, Kotlin ...
Lasso
<pre><code>[
sys_listtraits !>> 'xml_tree_trait' ? include('xml_tree.lasso')
local(lang = array)
local(f = curl('http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000')->result->asString)
local(ff) = xml_tree(#f)
local(lis = #ff->body->div(3)->div(3)->div(3)->div->ul->getnodes)
with li in #lis do => {
local(title = #li->a->attribute('title'))
#title->removeLeading('Category:')
local(num = #li->asString->split('(')->last)
#num->removeTrailing(')')
#num->removeTrailing('members')
#num->removeTrailing('member')
#num->trim
#num = integer(#num)
#lang->insert(#title = #num)
}
local(c = 1)
with l in #lang
order by #l->second descending
do => {^
#c++
'. '+#l->second + ' - ' + #l->first+'\r'
^}
]</code></pre>
- Output:
1. 759 - Tcl 2. 724 - Racket 3. 707 - Python 4. 692 - Programming Tasks 5. 672 - C 6. 643 - J 7. 635 - Perl 6 8. 632 - D 9. 627 - PicoLisp 10. 617 - Ruby ...
M2000 Interpreter
Based on BBC BASIC idea, and using M2000 Rinstr() and objects as Inventories, Document, and Microsoft.XMLHTTP for downloading (async use). Results also copy to Clipboard. We can use Msxml2.ServerXMLHTTP (code is the same, only name of object change).
Update: Numbers above 999 get a comma (,) so we have to drop this using Filter$()
Module RankLanguages {
Const Part1$="<a href="+""""+ "/wiki/Category", Part2$="member"
Const langHttp$="http://rosettacode.org/wiki/Category:Programming_Languages"
Const categoriesHttp$="http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000"
Def long m, i,j, tasks, counter, limit, T, t1
Def string LastLang$, job$
Document final$, languages$, categories$
httpGet$=lambda$ (url$, timeout=1000)->{
Declare htmldoc "Msxml2.ServerXMLHTTP"
With htmldoc , "readyState" as ready
Report "Download:"+url$
Method htmldoc "open","get", url$, True
Method htmldoc "send"
Profiler
While Ready<>4 {
Wait 20
Print Over format$("Wait: {0:3} sec", timecount/1000)
If timecount>timeout then Exit
}
If ready=4 Then With htmldoc, "responseText" as ready$ : =ready$
Declare htmldoc Nothing
print
}
languages$=httpGet$(langHttp$, 30000)
If Doc.Len(languages$)=0 then Error "File download failed (languages)"
Inventory Lang
m=Paragraph(languages$, 0)
If Forward(languages$,m) then {
While m {
job$=Paragraph$(languages$,(m))
If Instr(job$, part1$) Else Continue
i = Instr(job$, "</a>")
If i Else Continue ' same as If i=0 Then Continue
j = i
i=Rinstr(job$, ">", -i)
If i Else Continue
LastLang$=MID$(job$, i+1, j-i-1)
if Instr(job$, "Category:"+lastlang$) then Append lang, lastlang$:=0 : Print Over format$("Languages: {0}", len(lang))
}
}
Print
Document categories$=httpGet$(categoriesHttp$, 30000)
If Doc.Len(categories$)=0 then Error "File download failed (categories)"
limit=Doc.Par(categories$)
If limit<Len(Lang) then Error "Invalid data"
Refresh
set slow
m=Paragraph(categories$, 0)
counter=0
If Forward(categories$,m) then {
While m {
job$=Paragraph$(categories$,(m))
counter++
Print Over format$("{0:2:-6}%", counter/limit*100)
i=Instr(job$, part2$)
If i Else Continue
i=Rinstr(job$, "(", -i)
If i Else Continue
tasks=Val(Filter$(Mid$(job$, i+1),","))
If tasks Else Continue
i=Rinstr(job$, "<", -i)
If i Else Continue
j = i
i=Rinstr(job$, ">", -i)
If i Else Continue
LastLang$=MID$(job$, i+1, j-i-1)
If Exist(Lang, LastLang$) Then {
Return Lang, LastLang$:=Lang(LastLang$)+tasks
}
}
}
Print
\\ this type of inventory can get same keys
\\ also has stable sort
Report "Make Inventory list by Task"
Inventory queue ByTask
t1=Len(Lang)
T=Each(Lang)
While T {
Append ByTask, Eval(T):=Eval$(T!)
Print Over format$("Complete: {0} of {1}", T^+1, t1 )
}
Print
Report "Sort by task (stable sort, sort keys as numbers)"
Sort descending ByTask as number
Report "Make List"
T=Each(ByTask)
final$="Sample output on "+Date$(Today, 1033, "long date")+{:
}
While T {
final$=format$("rank:{0::-4}. {1:-5} entries - {2}", T^+1, Eval$(T!), Eval$(T))+{
}
}
Report "Copy to Clipboard"
clipboard final$
\\ present to console with 3/4 fill lines then stop for space bar or mouse click to continue
Report final$
}
RankLanguages
- Output:
Sample output on Saturday, June 22, 2019: rank: 1. 1149 entries - Go rank: 2. 1084 entries - Perl 6 rank: 3. 1061 entries - Python rank: 4. 1045 entries - Kotlin rank: 5. 1044 entries - Julia rank: 6. 1033 entries - Phix rank: 7. 1026 entries - Perl rank: 8. 991 entries - Racket rank: 9. 951 entries - C rank: 10. 944 entries - J rank: 11. 938 entries - Zkl rank: 12. 930 entries - Tcl rank: 13. 910 entries - REXX rank: 14. 909 entries - Java rank: 15. 883 entries - Ruby rank: 16. 881 entries - D rank: 17. 869 entries - Haskell rank: 18. 814 entries - Sidef rank: 19. 801 entries - Scala rank: 20. 779 entries - C sharp rank: 21. 775 entries - PicoLisp rank: 22. 772 entries - C++ rank: 23. 748 entries - Mathematica rank: 24. 678 entries - Common Lisp rank: 25. 668 entries - Ada rank: 26. 639 entries - JavaScript rank: 27. 633 entries - Lua rank: 28. 628 entries - AutoHotkey rank: 29. 611 entries - Ring rank: 30. 595 entries - Factor rank: 31. 594 entries - Clojure rank: 32. 590 entries - Unicon rank: 33. 566 entries - ALGOL 68 rank: 34. 563 entries - Nim rank: 35. 563 entries - PureBasic rank: 36. 560 entries - BBC BASIC rank: 37. 559 entries - Fortran rank: 38. 556 entries - OCaml rank: 39. 540 entries - PARI/GP rank: 40. 538 entries - F Sharp rank: 41. 532 entries - Icon rank: 42. 517 entries - Elixir rank: 43. 497 entries - FreeBASIC rank: 44. 495 entries - Erlang rank: 45. 485 entries - Rust rank: 46. 473 entries - PowerShell rank: 47. 462 entries - Jq rank: 48. 456 entries - Pascal rank: 49. 453 entries - AWK rank: 50. 450 entries - Forth rank: 51. 448 entries - Seed7 rank: 52. 435 entries - R rank: 53. 414 entries - Groovy rank: 54. 403 entries - PL/I rank: 55. 401 entries - PHP rank: 56. 383 entries - VBA rank: 57. 361 entries - Scheme rank: 58. 359 entries - MATLAB rank: 59. 353 entries - Swift rank: 60. 346 entries - M2000 Interpreter rank: 61. 343 entries - Maple rank: 62. 337 entries - Liberty BASIC rank: 63. 314 entries - Run BASIC rank: 64. 309 entries - Prolog .......... rank: 685. 1 entries - Jacquard Loom rank: 686. 1 entries - Kamailio Script rank: 687. 1 entries - Lambda Prolog rank: 688. 1 entries - LibreOffice Basic rank: 689. 1 entries - MAPPER rank: 690. 1 entries - MEL rank: 691. 1 entries - MiniZinc rank: 692. 1 entries - Mond rank: 693. 1 entries - Monkey rank: 694. 1 entries - NASL rank: 695. 1 entries - Neat rank: 696. 1 entries - NewtonScript rank: 697. 1 entries - Nickle rank: 698. 1 entries - Nix rank: 699. 1 entries - Opa rank: 700. 1 entries - Pare rank: 701. 1 entries - Qore rank: 702. 1 entries - Rapira rank: 703. 1 entries - RPGIV rank: 704. 1 entries - Setl4 rank: 705. 1 entries - Soar rank: 706. 1 entries - SoneKing Assembly rank: 707. 1 entries - Supernova rank: 708. 1 entries - SuperTalk rank: 709. 1 entries - Terra rank: 710. 1 entries - TestML rank: 711. 1 entries - WebAssembly rank: 712. 1 entries - Wollok rank: 713. 1 entries - Xanadu rank: 714. 1 entries - Ya rank: 715. 1 entries - МiniZinc rank: 716. 0 entries - AngelScript rank: 717. 0 entries - Binary Lambda Calculus rank: 718. 0 entries - EhBASIC rank: 719. 0 entries - Epigram rank: 720. 0 entries - FLORA-2 rank: 721. 0 entries - Florid rank: 722. 0 entries - Gerbil rank: 723. 0 entries - LC2200 Assembly rank: 724. 0 entries - Leon rank: 725. 0 entries - Livecode rank: 726. 0 entries - LLP rank: 727. 0 entries - Loglan82 rank: 728. 0 entries - Lolli rank: 729. 0 entries - Lygon rank: 730. 0 entries - ObjectIcon rank: 731. 0 entries - PL/B rank: 732. 0 entries - Plan rank: 733. 0 entries - Reduce rank: 734. 0 entries - Rubylog rank: 735. 0 entries - S BASIC rank: 736. 0 entries - SimpleLang rank: 737. 0 entries - Star rank: 738. 0 entries - X10 rank: 739. 0 entries - XS
Maple
count_sizes := proc(arr_name,arr_pop,i,lst)
local index := i;
local language;
for language in lst do
language := language[1]:
arr_name(index) := txt["query"]["pages"][language]["title"][10..]:
if(assigned(txt["query"]["pages"][language]["categoryinfo"]["size"])) then
arr_pop(index) := txt["query"]["pages"][language]["categoryinfo"]["size"]:
else:
arr_pop(index) := 0:
end if:
index++:
end do:
return index:
end proc:
txt := JSON:-ParseFile("http://rosettacode.org/mw/api.php?action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=350&prop=categoryinfo&format=json"):
arr_name := Array():
arr_pop := Array():
i := count_sizes(arr_name, arr_pop, 1, [indices(txt["query"]["pages"])]):
while (assigned(txt["continue"]["gcmcontinue"])) do
continue := txt["continue"]["gcmcontinue"]:
txt := JSON:-ParseFile(cat("http://rosettacode.org/mw/api.php?action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=350&prop=categoryinfo&format=json", "&continue=", txt["continue"]["continue"], "&gcmcontinue=", txt["continue"]["gcmcontinue"])):
i:=count_sizes(arr_name,arr_pop,i,[indices(txt["query"]["pages"])]):
end do:
arr_name:= arr_name[sort(arr_pop,output=permutation)]:
arr_pop := sort(arr_pop, output=sorted):
i := i-1:
for x from i to 1 by -1 do
printf("rank %d %d examples %s\n", i-x+1, arr_pop[x], arr_name[x]):
end do:
- Output:
#10:30 AM 10/05/2018 rank 1 1002 examples Kotlin rank 2 977 examples Racket rank 3 977 examples Python rank 4 949 examples Perl 6 rank 5 918 examples Tcl rank 6 898 examples C rank 7 891 examples J rank 8 879 examples Zkl rank 9 870 examples Java rank 10 860 examples D ... rank 680 0 examples Epigram rank 681 0 examples LLP rank 682 0 examples Lolli rank 683 0 examples Leon rank 684 0 examples Florid rank 685 0 examples Loglan82
Mathematica /Wolfram Language
Languages = Flatten[Import["http://rosettacode.org/wiki/Category:Programming_Languages","Data"][[1,1]]];
Languages = Most@StringReplace[Languages, {" " -> "_", "+" -> "%2B"}];
b = {#, If[# === {}, 0, #[[1]]]&@( StringCases[Import["http://rosettacode.org/wiki/Category:"<>#,"Plaintext"],
"category, out of " ~~ x:NumberString ~~ " total" ->x])} &/@ Languages;
For[i = 1, i < Length@b , i++ , Print[i, ". ", #[[2]], " - ", #[[1]] ]&@ Part[Reverse@SortBy[b, Last], i]]
- Output
- As of 29 February 2012:
1. 637 - Tcl 2. 576 - C 3. 558 - J 4. 538 - Go 5. 485 - Ada 6. 456 - D 7. 450 - Haskell 8. 441 - Mathematica 9. 432 - Java 10. 425 - Icon ...
Nim
import std/[Algorithm, httpclient, json, re, strformat, strutils]
const
LangSite = "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=500&format=json"
CatSite = "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000"
let regex = re"title=""Category:(.*?)"">.+?</a>.*\((.*) members\)"
type Rank = tuple[lang: string, count: int]
proc cmp(a, b: Rank): int =
result = cmp(b.count, a.count)
if result == 0: result = cmp(a.lang, b.lang)
proc add(langs: var seq[string]; fromJson: JsonNode) =
for entry in fromJson{"query", "categorymembers"}:
let title = entry["title"].getStr()
if title.startsWith("Category:"):
langs.add title[9..^1]
var client = newHttpClient()
var langs: seq[string]
var url = LangSite
while true:
let response = client.get(url)
if response.status != $Http200: break
let fromJson = response.body.parseJson()
langs.add fromJson
if "continue" notin fromJson: break
let cmcont = fromJson{"continue", "cmcontinue"}.getStr
let cont = fromJson{"continue", "continue"}.getStr
url = LangSite & fmt"&cmcontinue={cmcont}&continue={cont}"
var ranks: seq[Rank]
for line in client.getContent(CatSite).findAll(regex):
let lang = line.replacef(regex, "$1")
if lang in langs:
let count = parseInt(line.replacef(regex, "$2").replace(",", "").strip())
ranks.add (lang, count)
ranks.sort(cmp)
for i, rank in ranks:
echo &"{i + 1:3} {rank.count:4} - {rank.lang}"
Output:
1 1626 - Phix 2 1620 - Wren 3 1587 - Julia 4 1574 - Raku 5 1533 - Go 6 1520 - Perl 7 1466 - Python 8 1430 - Nim 9 1348 - J 10 1264 - C 11 1198 - Ruby 12 1185 - Mathematica 13 1164 - Java 14 1160 - Haskell 15 1155 - C++ 16 1153 - REXX 17 1136 - Kotlin 18 1131 - FreeBASIC 19 1100 - Racket 20 1027 - Jq 21 1014 - 11l 22 1012 - Zkl 23 1004 - Sidef 24 997 - Factor 25 987 - D 26 980 - Tcl 27 938 - Ada 28 926 - C sharp 29 923 - Scala 30 906 - ALGOL 68 31 896 - Rust 32 893 - Lua 33 849 - PicoLisp 34 843 - F Sharp 35 824 - AutoHotkey 36 818 - Ring 37 793 - Delphi 38 785 - JavaScript 39 778 - Arturo 40 776 - XPL0 ...
Objeck
use HTTP;
use RegEx;
use XML;
use Collection;
class RosettaRank {
function : Main(args : String[]) ~ Nil {
langs_xml := "";
client := HttpClient->New();
in := client->Get("http://rosettacode.org/mw/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=5000&format=xml");
each(i : in) {
langs_xml += in->Get(i)->As(String);
};
langs := StringSet->New();
parser := XmlParser->New(langs_xml);
if(parser->Parse()) {
# get first item
results := parser->FindElements("/api/query/categorymembers/cm");
each(i : results) {
element := results->Get(i)->As(XmlElement);
name := element->GetAttribute("title")->GetValue();
offset := name->Find(':');
if(offset > -1) {
lang := name->SubString(offset + 1, name->Size() - offset - 1);
langs->Insert(lang->ReplaceAll(" ", " "));
};
};
};
langs_counts := IntMap->New();
client := HttpClient->New();
html := client->Get("http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000");
each(i : html) {
lines := html->Get(i)->As(String);
html_elements := lines->Split("\n");
each(j : html_elements) {
element := html_elements[j];
name : String; count : String;
regex := RegEx->New("<li><a href=\"(\\w|\\s|/|\\?|\\&|;|:|#)+\"\\stitle=\"Category:(\\w|\\s|#)+\">");
found := regex->FindFirst(element);
if(found <> Nil) {
group1 := found->Size();
regex := RegEx->New("(\\w|\\s)+");
found := regex->Match(element, group1);
if(found <> Nil & found->Size() > 0) {
name := found;
# skip over some junk characters
group2 := group1 + found->Size() + 10;
regex := RegEx->New("\\s\\(");
found := regex->Match(element, group2);
if(found <> Nil) {
group3 := group2 + found->Size();
regex := RegEx->New("\\d+");
found := regex->Match(element, group3);
if(found <> Nil & found->Size() > 0) {
count := found;
};
};
};
};
if(name <> Nil & count <> Nil) {
if(langs->Has(name)) {
langs_counts->Insert(count->ToInt(), name);
};
name := Nil; count := Nil;
};
};
};
keys := langs_counts->GetKeys();
count := 1;
for(i := keys->Size() - 1; i >= 0; i -=1;) {
key := keys->Get(i);
IO.Console->Print(count)->Print(". ")->Print(key)->Print(" - ")->PrintLine(langs_counts->Find(key)->As(String));
count += 1;
};
}
}
1. 849 - Tcl 2. 826 - Racket 3. 821 - Python 4. 759 - J 5. 757 - Ruby 6. 751 - Perl 6 7. 743 - C 8. 736 - D 9. 728 - Go 10. 696 - Perl ...
ooRexx
/* REXX ---------------------------------------------------------------
* Create a list of Rosetta Code languages showing the number of tasks
* This program's logic is basically that of the REXX program
* rearranged to my taste and utilizing the array class of ooRexx
* which offers a neat way of sorting as desired, see :CLASS mycmp below
* For the input to this program open these links:
* http://rosettacode.org/wiki/Category:Programming_Languages
* http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000
* and save the pages as LAN.txt and CAT.txt, respectively
* Output: RC_POP.txt list of languages sorted by popularity
* If test=1, additionally:
* RC_LNG.txt list of languages alphabetically sorted
* RC_TRN.txt list language name translations (debug)
*--------------------------------------------------------------------*/
test=1
name.='??'
l.=0
safe=''
x00='00'x
linfid='RC_LAN.txt'
linfid='LAN.txt' /* language file */
cinfid='CAT.txt' /* category file */
oid='RC_POP.txt'; 'erase' oid
If test Then Do
tid='RC.TRN.txt'; 'erase' tid
tia='RC_LNG.txt'; 'erase' tia
End
Call init
call read_lang /* process language file */
Call read_cat /* process category file */
Call ot words(lang_list) 'possible languages'
Call ot words(lang_listr) 'relevant languages'
llrn=words(lang_listr)
If test Then
Call no_member
a=.array~new /* create array object */
cnt.=0
Do i=1 By 1 While lang_listr<>''
Parse Var lang_listr ddu0 lang_listr
ddu=translate(ddu0,' ',x00)
a[i]=right(mem.ddu,3) name.ddu /* fill array element */
z=mem.ddu /* number of members */
cnt.z=cnt.z+1 /* number of such languages */
End
n=i-1 /* number of output lines */
a~sortWith(.mycmp~new) /* sort the array elements */
/* see :CLASS mycmp below */
/*---------------------------------------------------------------------
* and now create the output
*--------------------------------------------------------------------*/
Call o ' '
Call o center('timestamp: ' date() time('Civil'),79,'-')
Call o ' '
Call o right(lrecs,9) 'records read from file: ' linfid
Call o right(crecs,9) 'records read from file: ' cinfid
Call o right(llrn,9) 'relevant languages'
Call o ' '
rank=0
rank.=0
Do i=1 To n
rank=rank+1
Parse Value a[i] With o . 6 lang
ol=' rank: 'right(rank,3)' '||,
'('right(o,3) 'entries) 'lang
If cnt.o>1 Then Do
If rank.o=0 Then
rank.o=rank
ol=overlay(right(rank.o,3),ol,17)
ol=overlay('[tied]',ol,22)
End
Call o ol
End
Call o ' '
Call o center('+ end of list +',72)
Say 'Output in' oid
If test Then Do
b=.array~new /* create array object */
cnt.=0
Do i=1 By 1 While lang_list<>''
Parse Var lang_list ddu0 lang_list
ddu=translate(ddu0,' ',x00)
b[i]=right(mem.ddu,3) name.ddu /* fill array element */
End
n=i-1 /* number of output lines */
b~sortWith(.alpha~new) /* sort the array elements */
Call oa n 'languages'
Do i=1 To n
Call oa b[i]
End
Say 'Sorted list of languages in' tia
End
Exit
o:
Return lineout(oid,arg(1))
ot:
If test Then Call lineout tid,arg(1)
Return
oa:
If test Then Call lineout tia,arg(1)
Return
read_lang:
/*---------------------------------------------------------------------
* Read the language page to determine the list of possible languages
* Output: l.lang>0 for all languages found
* name.lang original name of uppercased language name
* lang_list list of uppercased language names
* lrecs number of records read from language file
*--------------------------------------------------------------------*/
l.=0
name.='??'
lang_list=''
Do lrecs=0 While lines(linfid)\==0
l=linein(linfid) /* read from language file */
l=translate(l,' ','9'x) /* turn tabs to blanks */
dd=space(l) /* remove extra blanks */
ddu=translate(dd)
If pos('AUTOMATED ADMINISTRATION',ddu)>0 Then /* ignore this */
Iterate
If pos('RETRIEVED FROM',ddu)\==0 Then /* this indicates the end */
Leave
If dd=='' Then /* ignore all blank lines. */
Iterate
If left(dd,1)\=='*' Then /* ignore lines w/o * */
Iterate
ddo=fix_lang(dd) /* replace odd language names */
If ddo<>dd Then Do /* show those that we found */
Call ot ' ' dd
Call ot '>' ddo
dd=ddo
End
Parse Var dd '*' dd "<" /* extract the language name */
ddu=strip(translate(dd)) /* translate to uppercase */
If name.ddu='??' Then
name.ddu=dd /* remember 1st original name */
l.ddu=l.ddu+1
ddu_=translate(ddu,x00,' ')
If wordpos(ddu_,lang_list)=0 Then
lang_list=lang_list ddu_
End
Return
read_cat:
/*---------------------------------------------------------------------
* Read the category page to get language names and number of members
* Output: mem.ddu number of members for (uppercase) Language ddu
* lang_listr the list of relevant languages
*--------------------------------------------------------------------*/
mem.=0
lang_listr=''
Do crecs=0 While lines(cinfid)\==0
l=get_cat(cinfid) /* read from category file */
l=translate(l,' ','9'x) /* turn tabs to blanks */
dd=space(l) /* remove extra blanks */
If dd=='' Then /* ignore all blank lines. */
Iterate
ddu=translate(dd)
ddo=fix_lang(dd) /* replace odd language names */
If ddo<>dd Then Do /* show those that we found */
Call ot ' ' dd
Call ot '>' ddo
dd=ddo
End
du=translate(dd) /* get an uppercase version. */
If pos('RETRIEVED FROM',du)\==0 Then /* this indicates the end */
Leave
Parse Var dd dd '<' "(" mems . /* extract the language name */
/* and the number of members */
dd=space(substr(dd,3))
_=translate(dd)
If \l._ Then /* not a known language */
Iterate /* ignore */
if pos(',', mems)\==0 then
mems=changestr(",", mems, '') /* remove commas. */
If\datatype(mems,'W') Then /* not a number of members */
Iterate /* ignore */
ddu=space(translate(dd))
mem.ddu=mem.ddu+mems /* set o add number of members*/
Call memory ddu /* list of relevant languages */
End
Return
get_cat:
/*---------------------------------------------------------------------
* get a (logical) line from the category file
* These two lines
* * Lotus 123 Macro Scripting
* </wiki/Category:Lotus_123_Macro_Scripting>�‎ (3 members)
* are returned as one line:
*-> * Lotus 123 Macro Scripting </wiki/Cate ... (3 members)
* we need language name and number of members in one line
*--------------------------------------------------------------------*/
Parse Arg fid
If safe<>'' Then
ol=safe
Else Do
If lines(fid)=0 Then
Return ''
ol=linein(fid)
safe=''
End
If left(ol,3)=' *' Then Do
Do Until left(r,3)==' *' | lines(fid)=0
r=linein(fid)
If left(r,3)==' *' Then Do
safe=r
Return ol
End
Else
ol=ol r
End
End
Return ol
memory:
ddu0=translate(ddu,x00,' ')
If wordpos(ddu0,lang_listr)=0 Then
lang_listr=lang_listr ddu0
Return
fix_lang: Procedure Expose old. new.
Parse Arg s
Do k=1 While old.k\=='' /* translate Unicode variations. */
If pos(old.k,s)\==0 Then
s=changestr(old.k,s,new.k)
End
Return s
init:
old.=''
old.1='UC++' /* '55432B2B'X */
new.1="µC++" /* old UC++ --?ASCII-8: µC++ */
old.2='МК-61/52' /* 'D09CD09A2D36312F3532'X */
new.2='MK-61/52' /* somewhere a mistranslated: MK- */
old.3='Déjà Vu' /* '44C3A96AC3A0205675'X */
new.3='Déjà Vu' /* Unicode +¬j+á --?ASCII-8: Déjá */
old.4='Caché' /* '43616368C3A9'X */
new.4='Caché' /* Unicode ach+¬ --?ASCII-8: Caché */
old.5='ÎœC++' /* 'CE9C432B2B'X */
new.5="MC++" /* Unicode +£C++ --?ASCII-8: µC++ */
/*-----------------------------------------------------------------*/
Call ot 'Language replacements:'
Do ii=1 To 5
Call ot ' ' left(old.ii,10) left(c2x(old.ii),20) '->' new.ii
End
Call ot ' '
Return
no_member: Procedure Expose lang_list lang_listr tid x00 test
/*---------------------------------------------------------------------
* show languages found in language file that are not referred to
* in the category file
*--------------------------------------------------------------------*/
ll =wordsort(lang_list ) /* languages in language file */
llr=wordsort(lang_listr) /* languages in category file */
Parse Var ll l1 ll
Parse Var llr l2 llr
nn.=0
Do Forever
Select
When l1=l2 Then Do
If l1='' Then /* both lists empty */
Leave
Parse Var ll l1 ll /* get the next language */
Parse Var llr l2 llr /* -"- */
End
When l1<l2 Then Do /* in language file */
/* and not in category file */
z=nn.0+1
nn.z=' 'translate(l1,' ',x00) /* show in test output */
nn.0=z
Parse Var ll l1 ll /* next from language file */
End
Otherwise Do
Call ot '?? 'translate(l2,' ',x00) /* show in test output */
Say 'In category file but not in language file:'
Say '?? 'translate(l2,' ',x00)
Say 'Hit enter to proceed'
Pull .
Parse Var llr l2 llr /* next from category file */
End
End
End
Call ot nn.0 'Languages without members:' /* heading */
Do ii=1 To nn.0
Call ot nn.ii
End
Return
::CLASS mycmp MIXINCLASS Comparator
::METHOD compare
/**********************************************************************
* smaller number is considered higher
* numbers equal: higher language considered higher
* otherwise return lower
**********************************************************************/
Parse Upper Arg a,b
Parse Var a na +4 ta
Parse Var b nb +4 tb
Select
When na<<nb THEN res=1
When na==nb Then Do
If ta<<tb Then res=-1
Else res=1
End
Otherwise res=-1
End
Return res
::CLASS alpha MIXINCLASS Comparator
::METHOD compare
/**********************************************************************
* higher language considered higher
* otherwise return lower
**********************************************************************/
Parse Upper Arg a,b
Parse Var a na +4 ta
Parse Var b nb +4 tb
If ta<<tb Then res=-1
Else res=1
Return res
Output (the beginning):
------------------------timestamp: 24 Nov 2013 9:48am------------------------- 706 records read from file: LAN.txt 2204 records read from file: CAT.txt 502 relevant languages rank: 1 (760 entries) Tcl rank: 2 (724 entries) Racket rank: 3 (708 entries) Python rank: 4 (681 entries) C
Note: If MC++ and µC++ are the same, they should/could be added together to get 501 languages.
PascalABC.NET
Using web scraping. May 2024.
uses System.Net;
begin
ServicePointManager.SecurityProtocol := SecurityProtocolType(3072);
var wc := new WebClient;
wc.Encoding := Encoding.UTF8;
var s := wc.DownloadString('https://rosettacode.org/wiki/Special:Categories?limit=5000');
s.Matches('([^><]+)</a>.+\(([\d,]+) member')
.Select(x -> KV(x.Groups[1].Value,x.Groups[2].Value.Replace(',','').ToInteger))
.Where(x -> not x.Key.StartsWith('Pages'))
.OrderByDescending(pair -> pair.Value).Numerate.Take(10)
.PrintLines(x -> $'Rank: {x[0],3} ({x[1].Value} entries) {x[1].Key}')
end.
- Output:
Rank: 1 (1682 entries) Phix Rank: 2 (1675 entries) Wren Rank: 3 (1652 entries) Julia Rank: 4 (1622 entries) Raku Rank: 5 (1577 entries) Nim Rank: 6 (1552 entries) Go Rank: 7 (1548 entries) Perl Rank: 8 (1531 entries) Python Rank: 9 (1416 entries) J Rank: 10 (1343 entries) Java
Oz
Using web scraping. Does not filter non-language categories.
declare
[HTTPClient] = {Module.link ['x-ozlib://mesaros/net/HTTPClient.ozf']}
[Regex] = {Module.link ['x-oz://contrib/regex']}
fun {GetPage RawUrl}
Client = {New HTTPClient.urlGET init(inPrms(toFile:false toStrm:true) _)}
Url = {VirtualString.toString RawUrl}
OutParams
HttpResponseParams
in
{Client getService(Url ?OutParams ?HttpResponseParams)}
{Client closeAll(true)}
OutParams.sOut
end
fun {GetCategories Doc}
{Map {Regex.allMatches "<li><a[^>]+>([^<]+)</a> \\(([0-9]+) member" Doc}
fun {$ Match}
Category = {Regex.group 1 Match Doc}
Count = {String.toInt {ByteString.toString {Regex.group 2 Match Doc}}}
in
Category#Count
end
}
end
Url = "http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000"
{System.showInfo "Retrieving..."}
Doc = {GetPage Url}
{System.showInfo "Parsing..."}
Cs = {GetCategories Doc}
in
for
Cat#Count in {Sort Cs fun {$ _#C1 _#C2} C1 > C2 end}
I in 1..20
do
{System.showInfo I#". "#Count#" - "#Cat}
end
- Output:
1. 371 - Tcl 2. 369 - Programming Tasks 3. 338 - Python 4. 324 - Ruby 5. 306 - Haskell ... 17. 225 - Oz 18. 214 - C++ 19. 209 - JavaScript 20. 208 - ALGOL 68
Perl
By using the API
use 5.010;
use MediaWiki::API;
my $api =
MediaWiki::API->new( { api_url => 'http://rosettacode.org/w/api.php' } );
my @languages;
my $gcmcontinue;
while (1) {
my $apih = $api->api(
{
action => 'query',
generator => 'categorymembers',
gcmtitle => 'Category:Programming Languages',
gcmlimit => 250,
prop => 'categoryinfo',
gcmcontinue => $gcmcontinue
}
);
push @languages, values %{ $apih->{'query'}{'pages'} };
last if not $gcmcontinue = $apih->{'continue'}{'gcmcontinue'};
}
for (@languages) {
$_->{'title'} =~ s/Category://;
$_->{'categoryinfo'}{'size'} //= 0;
}
my @sorted_languages =
reverse sort { $a->{'categoryinfo'}{'size'} <=> $b->{'categoryinfo'}{'size'} }
@languages;
binmode STDOUT, ':encoding(utf8)';
my $n = 1;
for (@sorted_languages) {
printf "%3d. %20s - %3d\n", $n++, $_->{'title'},
$_->{'categoryinfo'}{'size'};
}
- Output:
1. Phix - 1576 2. Wren - 1569 3. Julia - 1540 4. Raku - 1520 5. Go - 1500 6. Perl - 1468 7. Python - 1422 8. Nim - 1403 9. J - 1278 10. C - 1213 ...
Phix
The distributed version also has an output_html option.
-- demo\rosetta\Rank_Languages.exw constant output_users = false, limit = 20, -- 0 to list all languages = "http://rosettacode.org/wiki/Category:Programming_Languages", categories = "http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000" include rosettacode_cache.e -- see Rosetta_Code/Count_examples#Phix function correct_name(string ri) ri = substitute(ri,`"`,`"`) ri = substitute(ri,`'`,`'`) ri = substitute(ri,"\xE2\x80\x99","'") ri = substitute(ri,"\xC3\xB6","o") ri = substitute(ri,"%3A",":") ri = substitute(ri,"%E2%80%93","-") ri = substitute(ri,"%E2%80%99","'") ri = substitute(ri,"%27","'") ri = substitute(ri,"%2B","+") ri = substitute(ri,"%C3%A8","e") ri = substitute(ri,"%C3%A9","e") ri = substitute(ri,"%C3%B6","o") ri = substitute(ri,"%C5%91","o") ri = substitute(ri,"%22",`"`) ri = substitute(ri,"%2A","*") ri = substitute(ri,"\xC2\xB5","u") ri = substitute(ri,"\xC3\xA0","a") ri = substitute(ri,"\xC3\xA6","a") ri = substitute(ri,"\xC3\xA9","e") ri = substitute(ri,"\xC3\xB4","o") ri = substitute(ri,"\xC5\x8D","o") ri = substitute(ri,"\xCE\x9C","u") ri = substitute(ri,"\xD0\x9C\xD0\x9A","MK") ri = substitute(ri,"\xE0\xAE\x89\xE0\xAE\xAF\xE0\xAE\xBF\xE0\xAE\xB0\xE0\xAF\x8D/","") ri = substitute(ri,"APEX","Apex") ri = substitute(ri,"uC++ ","UC++") ri = substitute(ri,`CASIO BASIC`,`Casio BASIC`) ri = substitute(ri,`Visual BASIC`,`Visual Basic`) ri = substitute(ri,`INTERCAL`,`Intercal`) ri = substitute(ri,`SETL4`,`Setl4`) ri = substitute(ri,`QBASIC`,`QBasic`) ri = substitute(ri,`RED`,`Red`) ri = substitute(ri,`OCTAVE`,`Octave`) ri = substitute(ri,`OoREXX`,`OoRexx`) return ri end function include builtins/sets.e constant cat_title = `title="Category:` function extract_names() sequence results = {} -- {rank,count,name} if get_file_type("rc_cache")!=FILETYPE_DIRECTORY then if not create_directory("rc_cache") then crash("cannot create rc_cache directory") end if end if -- 1) extract languages from eg title="Category:Phix" sequence language_names = {} string langs = open_download("languages.htm",languages), language_name langs = langs[1..match(`<div class="printfooter">`,langs)-1] integer start = match("<h2>Subcategories</h2>",langs), k while true do k = match(cat_title,langs,start) if k=0 then exit end if k += length(cat_title) start = find('"',langs,k) language_name = correct_name(langs[k..start-1]) language_names = append(language_names,language_name) end while -- 2) extract results from eg title="Category:Phix">Phix</a>?? (997 members)</li> -- but obviously only when we have found that language in the phase above. -- (note there is / ignore some wierd uncode-like stuff after the </a>...) string cats = open_download("categories.htm",categories) start = 1 while true do k = match(cat_title,cats,start) if k=0 then exit end if k += length(cat_title) start = find('"',cats,k) language_name = correct_name(cats[k..start-1]) start = match("</a>",cats,start)+4 if output_users then if length(language_name)>5 and language_name[-5..-1] = " User" then language_name = correct_name(language_name[1..-6]) else language_name = "" end if end if if length(language_name) and find(language_name,language_names) then while not find(cats[start],"(<") do start += 1 end while -- (ignore) string members = cats[start..find('<',cats,start+1)] members = substitute(members,",","") sequence res = scanf(members,"(%d member%s)<") results = append(results,{0,res[1][1],language_name}) end if end while results = sort_columns(results,{-2,3}) -- (descending 2nd column, then asc 3rd) --3) assign rank integer count, prev = 0, rank for i=1 to length(results) do count = results[i][2] if count=prev then results[i][1] = "=" else rank = i results[i][1] = sprint(rank) prev = count end if end for return results end function procedure show(sequence results) progress("") for i=1 to iff(limit?limit:length(results)) do printf(1,"%3s: %,d - %s\n",results[i]) end for end procedure show(extract_names())
- Output:
As of July 31st, 2019
Downloading rc_cache\languages.htm... Downloading rc_cache\categories.htm... 1: 1,156 - Go 2: 1,092 - Phix 3: 1,090 - Perl 6 4: 1,074 - Julia 5: 1,066 - Python 6: 1,046 - Kotlin 7: 1,026 - Perl 8: 991 - Racket 9: 953 - C 10: 945 - J 11: 943 - Zkl 12: 930 - Tcl 13: 915 - REXX 14: 910 - Java 15: 897 - Ruby 16: 892 - D 17: 872 - Haskell 18: 816 - Sidef 19: 814 - Scala 20: 786 - C sharp
PicoLisp
(load "@lib/http.l")
(for (I . X)
(flip
(sort
(make
(client "rosettacode.org" 80
"mw/index.php?title=Special:Categories&limit=5000"
(while (from "<li><a href=\"/wiki/Category:")
(let Cat (till "\"")
(from "(")
(when (format (till " " T))
(link (cons @ (ht:Pack Cat))) ) ) ) ) ) ) )
(prinl (align 3 I) ". " (car X) " - " (cdr X)) )
- Output (dec15):
1. 903 - Racket 2. 897 - Tcl 3. 863 - Python 4. 821 - J 5. 796 - Perl_6 6. 780 - Programming_Tasks 7. 778 - Ruby 8. 767 - C 9. 751 - Go 10. 745 - D ...
PowerShell
$get1 = (New-Object Net.WebClient).DownloadString("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Languages&cmlimit=700&format=json")
$get2 = (New-Object Net.WebClient).DownloadString("http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000")
$match1 = [regex]::matches($get1, "`"title`":`"Category:(.+?)`"")
$match2 = [regex]::matches($get2, "title=`"Category:([^`"]+?)`">[^<]+?</a>[^\(]*\((\d+) members\)")
$r = 1
$langs = $match1 | foreach { $_.Groups[1].Value.Replace("\","") }
$res = $match2 | sort -Descending {[Int]$($_.Groups[2].Value)} | foreach {
if ($langs.Contains($_.Groups[1].Value))
{
[pscustomobject]@{
Rank = "$r"
Members = "$($_.Groups[2].Value)"
Language = "$($_.Groups[1].Value)"
}
$r++
}
}
1..30 | foreach{
[pscustomobject]@{
"Rank 1..30" = "$($_)"
"Members 1..30" = "$($res[$_-1].Members)"
"Language 1..30" = "$($res[$_-1].Language)"
"Rank 31..60" = "$($_+30)"
"Members 31..60" = "$($res[$_+30].Members)"
"Language 31..60" = "$($res[$_+30].Language)"
}
}| Format-Table -AutoSize
Output: August 04, 2015
Rank 1..30 Members 1..30 Language 1..30 Rank 31..60 Members 31..60 Language 31..60 ---------- ------------- -------------- ----------- -------------- --------------- 1 887 Tcl 31 405 Seed7 2 877 Racket 32 397 Julia 3 853 Python 33 389 PL/I 4 798 J 34 387 Fortran 5 775 Ruby 35 386 ALGOL 68 6 766 Perl 6 36 376 Lua 7 758 C 37 369 Pascal 8 746 Go 38 367 R 9 740 D 39 364 Groovy 10 710 Perl 40 363 F Sharp 11 701 REXX 41 363 Forth 12 692 PicoLisp 42 358 PHP 13 682 Haskell 43 342 AWK 14 675 Mathematica 44 340 Sidef 15 652 Java 45 335 MATLAB 16 623 Ada 46 325 Liberty BASIC 17 591 AutoHotkey 47 297 Octave 18 562 C++ 48 287 Factor 19 551 Common Lisp 49 286 Scheme 20 548 Scala 50 285 NetRexx 21 532 BBC BASIC 51 284 Oforth 22 523 Icon 52 280 Oz 23 516 C sharp 53 274 Run BASIC 24 508 OCaml 54 272 E 25 502 Nim 55 271 Bracmat 26 488 PureBasic 56 268 PowerShell 27 487 Clojure 57 263 Prolog 28 455 Erlang 58 260 Lasso 29 441 PARI/GP 59 249 Delphi 30 434 JavaScript 60 239 Smalltalk
PowerShell: Using web scraping
$response = (New-Object Net.WebClient).DownloadString("http://rosettacode.org/wiki/Category:Programming_Languages")
$languages = [regex]::matches($response,'title="Category:(.*?)">') | foreach {$_.Groups[1].Value}
$response = [Net.WebClient]::new().DownloadString("http://rosettacode.org/w/index.php?title=Special:Categories&limit=5000")
$response = [regex]::Replace($response,'(\d+),(\d+)','$1$2')
$members = [regex]::matches($response,'<li><a[^>]+>([^<]+)</a>[^(]*[(](\d+) member[s]?[)]</li>') | foreach { [pscustomobject]@{
Members = [Int]($_.Groups[2].Value)
Language = [String]($_.Groups[1].Value)
}} | where {$languages.Contains($_.Language)} | sort -Descending Members
Get-Date -UFormat "Sample output on %d %B %Y at %R %Z"
$members | Select-Object -First 10 | foreach -Begin {$r, $rank, $count = 0, 0,-1} {
$r++
if ($count -ne $_.Members) {$rank = $r}
$count = $_.Members
$x = $_.Members.ToString("N0",[System.Globalization.CultureInfo]::CreateSpecificCulture('en-US'))
$entry = "($x entries)"
[String]::Format("Rank: {0,2} {1,15} {2}",$rank,$entry,$_.Language)
}
- Output:
Sample output on 13 septembre 2019 at 12:17 +02 Rank: 1 (1,177 entries) Go Rank: 2 (1,116 entries) Phix Rank: 3 (1,107 entries) Perl 6 Rank: 4 (1,104 entries) Julia Rank: 5 (1,080 entries) Python Rank: 6 (1,053 entries) Kotlin Rank: 7 (1,048 entries) Perl Rank: 8 (1,045 entries) Racket Rank: 9 (970 entries) C Rank: 10 (960 entries) Zkl
PowerShell: Using MediaWiki API method
$languages = @{}
$Body = @{
format = 'json'
action = 'query'
generator = 'categorymembers'
gcmtitle = 'Category:Programming Languages'
gcmlimit = '200'
gcmcontinue = ''
continue = ''
prop = 'categoryinfo'
}
$params = @{
Method = 'Get'
Uri = 'http://rosettacode.org/mw/api.php'
Body = $Body
}
while ($true) {
$response = Invoke-RestMethod @params
$response.query.pages.PSObject.Properties | ForEach-Object {
if (($_.value.PSObject.Properties.Name -Contains 'title') -and ($_.value.PSObject.Properties.Name -Contains 'categoryinfo')) {
$languages[$_.value.title.replace('Category:', '')] = $_.value.categoryinfo.size
}
}
if ($response.PSObject.Properties.Name -Contains 'continue') {
$gcmcontinue = $response.continue.gcmcontinue
$params.Body.gcmcontinue = $gcmcontinue
} else {
break
}
}
$members = $languages.GetEnumerator() | sort -Descending value
Get-Date -UFormat "Sample output on %d %B %Y at %R %Z"
$members | Select-Object -First 10 | foreach -Begin {$r, $rank, $count = 0, 0,-1} {
$r++
if ($count -ne $_.Members) {$rank = $r}
$count = $_.Value
$x = $_.Value.ToString("N0",[System.Globalization.CultureInfo]::CreateSpecificCulture('en-US'))
$entry = "($x entries)"
[String]::Format("Rank: {0,2} {1,15} {2}",$rank, $entry, $_.Name)
}
- Output:
Sample output on 05 juillet 2022 at 19:53 +02 Rank: 1 (1,552 entries) Phix Rank: 2 (1,545 entries) Wren Rank: 3 (1,521 entries) Julia Rank: 4 (1,498 entries) Go Rank: 5 (1,497 entries) Raku Rank: 6 (1,456 entries) Perl Rank: 7 (1,402 entries) Nim Rank: 8 (1,401 entries) Python Rank: 9 (1,206 entries) C Rank: 10 (1,180 entries) J
PureBasic
Using MediaWiki API method
Procedure handleError(value, msg.s)
If value = 0
MessageRequester("Error", msg)
End
EndIf
EndProcedure
Structure languageInfo
name.s
pageCount.i
EndStructure
#JSON_web_data = 0 ;ID# for our parsed JSON web data object
Define NewList languages.languageInfo()
Define blah.s, object_val, allPages_mem, title_mem, page_mem, categoryInfo_mem, continue_mem
Define url$, title$, currentPage$, language$, langPageCount, gcmcontinue$, *bufferPtr
handleError(InitNetwork(), "Unable to initialize network functions.")
Repeat
url$ = "http://www.rosettacode.org/mw/api.php?action=query" +
"&generator=categorymembers&gcmtitle=Category:Programming%20Languages" +
"&gcmlimit=500" + "&gcmcontinue=" + gcmcontinue$ +
"&prop=categoryinfo&format=json"
*bufferPtr = ReceiveHTTPMemory(url$)
handleError(*bufferPtr, "Unable to receive web page data.")
If CatchJSON(#JSON_web_data, *bufferPtr, MemorySize(*bufferPtr)) = 0
MessageRequester("Error", JSONErrorMessage() + " at position " +
JSONErrorPosition() + " in line " +
JSONErrorLine() + " of JSON web Data")
End
EndIf
FreeMemory(*bufferPtr)
object_val = JSONValue(#JSON_web_data)
allPages_mem = GetJSONMember(GetJSONMember(object_val, "query"), "pages")
If ExamineJSONMembers(allPages_mem)
While NextJSONMember(allPages_mem)
page_mem = JSONMemberValue(allPages_mem)
title_mem = GetJSONMember(page_mem, "title")
If title_mem
title$ = GetJSONString(title_mem)
If Left(title$, 9) = "Category:"
language$ = Mid(title$, 10)
categoryInfo_mem = GetJSONMember(page_mem, "categoryinfo")
If categoryInfo_mem
langPageCount = GetJSONInteger(GetJSONMember(categoryInfo_mem, "pages"))
Else
langPageCount = 0
EndIf
AddElement(languages())
languages()\name = language$
languages()\pageCount = langPageCount
EndIf
EndIf
Wend
EndIf
;check for continue
continue_mem = GetJSONMember(object_val, "continue")
If continue_mem
gcmcontinue$ = GetJSONString(GetJSONMember(continue_mem, "gcmcontinue"))
Else
gcmcontinue$ = ""
EndIf
FreeJSON(#JSON_web_data)
Until gcmcontinue$ = ""
;all data has been aquired, now process and display it
SortStructuredList(languages(), #PB_Sort_Descending, OffsetOf(languageInfo\pageCount), #PB_Integer)
If OpenConsole()
If ListSize(languages())
Define i, *startOfGroupPtr.languageInfo, *lastElementPtr, groupSize, rank
Define outputSize = 100, outputLine
PrintN(Str(ListSize(languages())) + " languages." + #CRLF$)
LastElement(languages())
*lastElementPtr = @languages() ;pointer to last element
FirstElement(languages())
*startOfGroupPtr = @languages() ;pointer to first element
groupSize = 1
rank = 1
While NextElement(languages())
If languages()\pageCount <> *startOfGroupPtr\pageCount Or *lastElementPtr = @languages()
;display a group of languages at the same rank
ChangeCurrentElement(languages(), *startOfGroupPtr)
For i = 1 To groupSize
;display output in groups to allow viewing of all entries
If outputLine = 0
PrintN(" Rank Tasks Language")
PrintN(" ------ ----- --------")
EndIf
PrintN(RSet(Str(rank), 6) + ". " +
RSet(Str(languages()\pageCount), 4) + " " +
languages()\name)
outputLine + 1
If outputLine >= outputSize
Print(#CRLF$ + #CRLF$ + "Press ENTER to continue" + #CRLF$): Input()
outputLine = 0
EndIf
NextElement(languages())
Next
rank + groupSize
groupSize = 1
*startOfGroupPtr = @languages()
Else
groupSize + 1
EndIf
Wend
Else
PrintN("No language categories found.")
EndIf
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf
Sample output:
608 languages. Rank Tasks Language ------ ----- -------- 1. 904 Racket 2. 894 Tcl 3. 852 Python 4. 836 J 5. 803 Perl 6 6. 787 Ruby 7. 772 C 8. 752 Go 9. 743 D 10. 728 Perl 11. 726 REXX 12. 702 Haskell 13. 697 Java 14. 696 PicoLisp 15. 693 Zkl 16. 687 Mathematica 17. 625 Ada 18. 603 C++ 18. 603 Sidef 18. 603 AutoHotkey 21. 578 Unicon 22. 574 Common Lisp 23. 558 Scala 24. 530 BBC BASIC 25. 527 C sharp 26. 520 Icon 27. 507 OCaml 28. 503 Nim 29. 497 PureBasic ..... 514. 0 Rubylog 514. 0 Refal 514. 0 QuakeC 514. 0 Mirelle 514. 0 .QL 514. 0 M680x0 514. 0 Datalog 514. 0 Cilk++ 514. 0 Cecil 514. 0 AspectC++ 514. 0 8080 Assembly 514. 0 OpenC++ 514. 0 AMPL 514. 0 UserRPL 514. 0 TeLa 514. 0 UScript 514. 0 TAL 514. 0 Zonnon 514. 0 Superbase BASIC 514. 0 VAX Assembly 514. 0 Star 514. 0 VRML 514. 0 WML 514. 0 X10 514. 0 XS 514. 0 XBase 514. 0 UC++ 514. 0 True BASIC 514. 0 Thistle
Using web scraping method
;Uses a web scraping method.
;It is limited to only retrieving 5000 language categories and the counts contain
;some slight inaccuracies.
Structure Language
count.i
Name.s
EndStructure
Dim Row.Language(5000)
Procedure handleError(value, msg.s)
If value = 0
MessageRequester("Error", msg)
End
EndIf
EndProcedure
handleError(InitNetwork(), "Unable to initialize network functions.")
; Lines have been split to fit RC's 80 char preferences
ignore$ = "Basic language learning Encyclopedia Implementations " +
"Language Implementations Language users " +
"Maintenance/OmitCategoriesCreated Programming Languages " +
"Programming Tasks RCTemplates Solutions by Library Solutions by " +
"Programming Language Solutions by Programming Task Unimplemented " +
"tasks by language WikiStubs Examples needing attention " +
"Impl needed"
url$ = "http://www.rosettacode.org/mw/index.php?" +
"title=Special:Categories&limit=5000"
ReceiveHTTPFile(url$, "special.htm")
ReadFile(0, "special.htm", #PB_UTF8)
While Not Eof(0)
i + 1
x1$ = ReadString(0)
x2$ = Mid(x1$, FindString(x1$, "member", 1) - 4 , 3)
Row(i)\count = Val(Trim(RemoveString(x2$, "(")))
x3$ = Mid(x1$, FindString(x1$, Chr(34) + ">", 1) + 2, 30)
Row(i)\Name = Left(x3$, FindString(x3$, "<", 1) - 1)
If FindString(ignore$, Row(i)\Name, 1) Or Row(i)\Name = ""
Row(i)\count = 0
EndIf
Wend
offset=OffsetOf(Language\count)
SortStructuredArray(Row(), #PB_Sort_Descending, offset, #PB_Integer)
OpenConsole()
For i = 0 To 29
PrintN( Str(i + 1) + ". " + Str(Row(i)\count) + " - " + Row(i)\Name)
Next
Input()
Sample output:
1. 907 - Racket 2. 898 - Tcl 3. 868 - Python 4. 839 - J 5. 807 - Perl 6 6. 790 - Ruby 7. 756 - Go 8. 746 - D 9. 732 - Perl 10. 729 - REXX 11. 705 - Haskell 12. 700 - Java 13. 699 - PicoLisp 14. 694 - Zkl 15. 690 - Mathematica 16. 629 - Ada 17. 606 - C++ 18. 606 - AutoHotkey 19. 604 - Sidef 20. 581 - Unicon 21. 577 - Common Lisp 22. 561 - Scala 23. 533 - BBC BASIC 24. 530 - C sharp 25. 523 - Icon 26. 510 - OCaml 27. 504 - Nim 28. 500 - PureBasic 29. 494 - Clojure 30. 491 - JavaScript
Python
Python: Using web scraping
Using requests
library.
import requests
import re
response = requests.get("http://rosettacode.org/wiki/Category:Programming_Languages").text
languages = re.findall('title="Category:(.*?)">',response)[:-3] # strip last 3
response = requests.get("http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000").text
response = re.sub('(\d+),(\d+)',r'\1'+r'\2',response) # strip ',' from popular languages above 999 members
members = re.findall('<li><a[^>]+>([^<]+)</a>[^(]*[(](\\d+) member[s]*[)]</li>',response) # find language and members
for cnt, (language, members) in enumerate(sorted(members, key=lambda x: -int(x[1]))[:15]): # show only top 15 languages
if language in languages:
print("{:4d} {:4d} - {}".format(cnt+1, int(members), language))
- Output (as of Dec 21, 2020):
1 1306 - Go 2 1275 - Phix 3 1265 - Julia 4 1257 - Raku 5 1196 - Python 6 1182 - Perl 7 1107 - Kotlin 8 1080 - C 9 1074 - Java 10 1061 - Racket 11 1022 - REXX 12 1012 - Zkl 13 1002 - J 14 983 - Ruby 15 972 - Haskell
Python: Using MediaWiki API method
import requests
import operator
import re
api_url = 'http://rosettacode.org/mw/api.php'
languages = {}
parameters = {
'format': 'json',
'action': 'query',
'generator': 'categorymembers',
'gcmtitle': 'Category:Programming Languages',
'gcmlimit': '200',
'gcmcontinue': '',
'continue': '',
'prop': 'categoryinfo'
}
while(True):
response = requests.get(api_url, params=parameters).json()
for k,v in response['query']['pages'].items():
if 'title' in v and 'categoryinfo' in v:
languages[v['title']]=v['categoryinfo']['size']
if 'continue' in response:
gcmcontinue = response['continue']['gcmcontinue']
# print(gcmcontinue)
parameters.update({'gcmcontinue': gcmcontinue})
else:
break
# report top 15 languages
for i, (language, size) in enumerate(sorted(languages.items(), key=operator.itemgetter(1), reverse=True)[:15]):
print("{:4d} {:4d} - {}".format(i+1, size, re.sub('Category:','',language))) # strip Category: from language
- Output (as of Dec 21, 2020):
1 1306 - Go 2 1275 - Phix 3 1265 - Julia 4 1257 - Raku 5 1196 - Python 6 1182 - Perl 7 1107 - Kotlin 8 1080 - C 9 1074 - Java 10 1061 - Racket 11 1022 - REXX 12 1012 - Zkl 13 1002 - J 14 983 - Ruby 15 972 - Haskell
R
library(rvest)
library(dplyr)
options(stringsAsFactors=FALSE)
# getting the required table from the rosetta website
langUrl <- "https://rosettacode.org/wiki/Rosetta_Code/Rank_languages_by_popularity/Full_list"
langs <- read_html(langUrl) %>%
html_nodes(xpath='/html/body/div/div/div[1]/div[3]/main/div[2]/div[3]/div[1]/table') %>%
html_table() %>%
data.frame() %>%
select(c("Rank","TaskEntries","Language"))
# changing the columns to required format
langs$Rank = paste("Rank: ",langs$Rank)
langs$TaskEntries = paste0("(", format(langs$TaskEntries, big.mark = ",")
," entries", ")")
names(langs) <- NULL
langs[1:10,]
- Output (as of October, 24, 2022):
1 Rank: 1 (1,589 entries) Phix 2 Rank: 1 (1,589 entries) Wren 3 Rank: 3 (1,552 entries) Julia 4 Rank: 4 (1,535 entries) Raku 5 Rank: 5 (1,500 entries) Go 6 Rank: 6 (1,485 entries) Perl 7 Rank: 7 (1,422 entries) Python 8 Rank: 8 (1,402 entries) Nim 9 Rank: 9 (1,293 entries) J 10 Rank: 10 (1,213 entries) C
Racket
#lang racket
(require racket/hash
net/url
json)
(define limit 15)
(define (replacer cat) (regexp-replace #rx"^Category:(.*?)$" cat "\\1"))
(define category "Category:Programming Languages")
(define entries "entries")
(define api-url (string->url "http://rosettacode.org/mw/api.php"))
(define (make-complete-url gcmcontinue)
(struct-copy url api-url
[query `([format . "json"]
[action . "query"]
[generator . "categorymembers"]
[gcmtitle . ,category]
[gcmlimit . "200"]
[gcmcontinue . ,gcmcontinue]
[continue . ""]
[prop . "categoryinfo"])]))
(define @ hash-ref)
(define table (make-hash))
(let loop ([gcmcontinue ""])
(define resp (read-json (get-pure-port (make-complete-url gcmcontinue))))
(hash-union! table
(for/hash ([(k v) (in-hash (@ (@ resp 'query) 'pages))])
(values (@ v 'title #f) (@ (@ v 'categoryinfo (hash)) 'size 0))))
(cond [(@ resp 'continue #f) => (λ (c) (loop (@ c 'gcmcontinue)))]))
(for/fold ([prev #f] [rank #f] #:result (void))
([item (in-list (sort (hash->list table) > #:key cdr))] [i (in-range limit)])
(match-define (cons cat size) item)
(define this-rank (if (equal? prev size) rank (add1 i)))
(printf "Rank: ~a ~a ~a\n"
(~a this-rank #:align 'right #:min-width 2)
(~a (format "(~a ~a)" size entries) #:align 'right #:min-width 14)
(replacer cat))
(values size this-rank))
Output on September 4, 2019:
Rank: 1 (1176 entries) Go Rank: 2 (1112 entries) Phix Rank: 3 (1107 entries) Perl 6 Rank: 4 (1099 entries) Julia Rank: 5 (1079 entries) Python Rank: 6 (1053 entries) Kotlin Rank: 7 (1038 entries) Racket Rank: 8 (1037 entries) Perl Rank: 9 (968 entries) C Rank: 10 (960 entries) Zkl Rank: 11 (945 entries) J Rank: 12 (935 entries) REXX Rank: 13 (930 entries) Tcl Rank: 14 (910 entries) Java Rank: 15 (904 entries) Ruby
Recent, occasionally (hourly-ish) updated output also available at: http://www.timb.net/popular-languages.html.
Raku
(formerly Perl 6)
Raku: Using the API
Note that this counts only the tasks. It does not include other non-task categories in the counts yielding more realistic, non-inflated numbers. Raku is Unicode aware and handles non-ASCII names natively. This does not attempt to 'unify' different language names that are the same behind the scenes as a result of Rosettacodes' capitalization peculiarities. (E.G. μC++, UC++ & ΜC++)
use HTTP::UserAgent;
use URI::Escape;
use JSON::Fast;
use Sort::Naturally;
my $client = HTTP::UserAgent.new;
my $url = 'https://rosettacode.org/w';
my $tablefile = './RC_Popularity.txt';
my %cat = (
'Programming_Tasks' => 'Task',
'Draft_Programming_Tasks' => 'Draft'
);
my %tasks;
for %cat.keys.sort -> $cat {
mediawiki-query(
$url, 'pages',
:generator<categorymembers>,
:gcmtitle("Category:$cat"),
:gcmlimit<350>,
:rawcontinue(),
:prop<title>
).map({ %tasks{%cat{$cat}}++ });
}
my %counts =
mediawiki-query(
$url, 'pages',
:generator<categorymembers>,
:gcmtitle<Category:Programming Languages>,
:gcmlimit<350>,
:rawcontinue(),
:prop<categoryinfo>
)
.map({
my $title = .<title>.subst(/^'Category:'/, '');
my $tasks = (.<categoryinfo><pages> || 0);
my $categories = (.<categoryinfo><subcats> || 0);
my $total = (.<categoryinfo><size> || 0);
$title => [$tasks ,$categories, $total]
});
my $out = open($tablefile, :w) or die "$!\n";
# Add table boilerplate and header
$out.say:
"\{|class=\"wikitable sortable\"\n",
"|+ As of { Date.today } :: {+%counts} Languages\n",
'!Rank!!Language!!Task<br>Entries!!Tasks<br>done %!!Non-task<br>Subcate-<br>gories!!Total<br>Categories'
;
my @bg = <#fff; #ccc;>;
my $ff = 0;
my $rank = 1;
my $ties = 0;
# Get sorted unique task counts
for %counts.values»[0].unique.sort: -* -> $count {
$ff++;
# Get list of tasks with this count
my @these = %counts.grep( *.value[0] == $count )».keys.sort: *.&naturally;
for @these {
$ties++;
$out.say:
"|- style=\"background-color: { @bg[$ff % 2] }\"\n"~
"|$rank\n"~
"|[[:Category:$_|]]\n"~
"|$count\n"~
"|{(100 * $count/%tasks<Draft Task>.sum).round(.01)} %\n"~
"|{%counts{$_}[1]}\n"~
"|{%counts{$_}[2]}"
}
$rank += $ties;
$ties = 0;
}
$out.say( "|}" );
$out.say('=' x 5, " query, download & processing: {(now - INIT now).round(.01)} seconds ", '=' x 5);
$out.close;
sub mediawiki-query ($site, $type, *%query) {
my $url = "$site/api.php?" ~ uri-query-string(
:action<query>, :format<json>, :formatversion<2>, |%query);
my $continue = '';
gather loop {
my $response = $client.get("$url&$continue");
my $data = from-json($response.content);
take $_ for $data.<query>.{$type}.values;
$continue = uri-query-string |($data.<query-continue>{*}».hash.hash or last);
}
}
sub uri-query-string (*%fields) {
join '&', %fields.map: { "{.key}={uri-escape .value}" }
}
- Abridged output:
See full output here.
Rank | Language | Task Entries |
Tasks done % |
Non-task Subcate- gories |
Total Categories |
---|---|---|---|---|---|
1 | Go | 1100 | 96.15 % | 4 | 1104 |
2 | Perl 6 | 1046 | 91.43 % | 4 | 1050 |
3 | Kotlin | 1029 | 89.95 % | 1 | 1030 |
4 | Python | 1017 | 88.9 % | 17 | 1034 |
5 | Phix | 991 | 86.63 % | 3 | 994 |
6 | Racket | 986 | 86.19 % | 3 | 989 |
7 | Perl | 963 | 84.18 % | 5 | 968 |
8 | Julia | 958 | 83.74 % | 3 | 961 |
9 | C | 940 | 82.17 % | 3 | 943 |
10 | Tcl | 925 | 80.86 % | 4 | 929 |
11 | Zkl | 918 | 80.24 % | 1 | 919 |
12 | J | 901 | 78.76 % | 3 | 904 |
13 | Java | 897 | 78.41 % | 3 | 900 |
14 | REXX | 886 | 77.45 % | 4 | 890 |
15 | D | 871 | 76.14 % | 3 | 874 |
16 | Ruby | 866 | 75.7 % | 3 | 869 |
17 | Haskell | 849 | 74.21 % | 3 | 852 |
18 | Scala | 789 | 68.97 % | 3 | 792 |
19 | Sidef | 787 | 68.79 % | 1 | 788 |
20 | PicoLisp | 772 | 67.48 % | 3 | 775 |
Raku: Using web scraping
Scraping the languages and categories pages. Raku automatically handles Unicode names correctly.
my $languages = qx{wget -O - 'http://rosettacode.org/wiki/Category:Programming_Languages'};
my $categories = qx{wget -O - 'http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000'};
my @lines = $languages.lines;
shift @lines until @lines[0] ~~ / '<h2>Subcategories</h2>' /;
my \languages = set gather for @lines {
last if / '/bodycontent' /;
take ~$0 if
/ '<li><a href="/wiki/Category:' .*? '" title="Category:' .*? '">' (.*?) '</a></li>' /;
}
@lines = $categories.lines;
my @results = sort -*.[0], gather for @lines {
take [+$1.subst(',', ''), ~$0] if
/ '<li><a href="/wiki/Category:' .*? '" title="Category:' .*? '">'
(.*?) <?{ ~$0 ∈ languages }>
'</a>' .*? '(' (<[, 0..9]>+) ' member' /;
}
for @results.kv -> $i, @l {
printf "%d:\t%4d - %s\n", $i+1, |@l;
}
- Output:
(As of 2018-10-28) Here we show only the top 10.
1: 1036 - Go 2: 1029 - Kotlin 3: 1014 - Python 4: 998 - Perl 6 5: 980 - Racket 6: 929 - Tcl 7: 926 - C 8: 910 - Perl 9: 904 - Zkl 10: 901 - J
Red
proccesses only languages with more than 25 entries to keep the list short
Red []
data: read http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000
lb: make block! 500
;;data: read %data.html ;; for testing save html and use flat file
arr: split data newline
k: "Category:"
;; exclude list:
exrule: [thru ["programming"
| "users"
| "Implementations"
| "Solutions by "
| "Members"
| "WikipediaSourced"
| "Typing/Strong"
| "Impl needed"
]
to end
]
foreach line arr [
unless find line k [continue]
parse line [ thru k thru ">" copy lang to "<" to end ] ;; extract/parse language
if 20 < length? lang [continue]
if parse lang [exrule] [continue] ;; exclude invalid
cnt: 0
;; parse number of entries
parse line [thru "</a>" thru "(" copy cnt to " member" (cnt: to-integer cnt ) to end]
if cnt > 25 [ append lb reduce [to-string lang cnt] ] ;; only process lang with > 25 entries
]
lb: sort/skip/compare lb 2 2 ;; sort series by entries
print reduce [ "Rank Entries Language" ] ;; header
last: 0
rank: 0
lb: tail lb ;; process the series backwards
until [
lb: skip lb -2
cnt: second lb
if cnt <> last [
rank: rank + 1
]
print rejoin [ pad/left rank 4 "." pad/left cnt 5 " - " first lb ]
last: cnt
head? lb ;; until head reached
]
Output: (30.12.2017)
Rank Entries Language 1. 961 - Racket 2. 959 - Python 3. 926 - Perl 6 4. 918 - Tcl 5. 900 - Kotlin 6. 883 - J 7. 875 - C 8. 859 - Zkl 9. 846 - Ruby 10. 833 - D 11. 828 - Go 12. 812 - REXX 13. 809 - Haskell 14. 802 - Java 15. 785 - Perl 16. 768 - PicoLisp 17. 733 - Sidef 18. 723 - Mathematica 19. 702 - Julia 20. 683 - Phix 21. 668 - C++ 22. 648 - Ada 23. 647 - Common Lisp 24. 637 - C sharp 25. 621 - AutoHotkey
REXX
(Native) REXX doesn't support web-page reading, so the aforementioned
- Rosetta Code categories and
- Rosetta Code languages
were downloaded to local files.
This program reads the Languages file and uses the contents of that file for a validation of
the categories file. This essentially is a perfect filter for the Rosetta Code categories file.
The catHeap variable in the REXX program is just a long string of all the records in the web-file of the
Rosetta Code categories, with a special character (sep) that separates each language entry (name).
The mechanism is to use a (sparse) stemmed array which holds only the names of languages which
(for most REXXes) uses a hashing algorithm to locate the entry (which is very fast).
Programming note: (REXX doesn't handle Unicode characters) some special cases that are translated:
- ╬£C++ translated into µC++ [Greek micro]
- ╨£╨Ü-61/52 translated into MK-61/52 [Cyrillic МК-61/52])
- ??-61/52 translated into MK-61/52 [Cyrillic МК-61/52])
- D├⌐j├á Vu translated into Déjà Vu
- Cach├⌐ translated into Caché
- F┼ìrmul├ª translated into Fôrmulæ
- உயிர்/Uyir translated into Uyir
- МiniZinc translated into MiniZinc
(The 3rd entry is most likely caused by the inability to render unsupported glyphs when it was first used to add that language.)
Code was added to support the renaming of the computer programming language Perl 6 ──► Raku.
Note that this REXX example properly ranks tied languages.
This REXX version sorts the tied languages by language name.
REXX program
/*REXX program reads two files and displays a ranked list of Rosetta Code languages.*/
parse arg catFID lanFID outFID . /*obtain optional arguments from the CL*/
call init /*initialize some REXX variables. */
call get /*obtain data from two separate files. */
call eSort #,0 /*sort languages along with members. */
call tSort /* " " that are tied in rank.*/
call eSort #,1 /* " " along with members. */
call out /*create the RC_POP.OUT (output) file.*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: parse arg _; do jc=length(_)-3 to 1 by -3; _= insert(",",_,jc); end; return _
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*pluralizer.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
eSort: procedure expose #. @. !tr.; arg N,p2; h= N /*sort: number of members*/
do while h>1; h= h % 2 /*halve number of records*/
do i=1 for N-h; j= i; k= h + i /*sort this part of list.*/
if p2 then do while !tR.k==!tR.j & @.k>@.j /*this uses a hard swap ↓*/
@= @.j; #= !tR.j; @.j= @.k; !tR.j= !tR.k; @.k= @; !tR.k= #
if h>=j then leave; j= j - h; k= k - h
end /*while !tR.k==···*/
else do while #.k<#.j /*this uses a hard swap ↓*/
@= @.j; #= #.j; @.j= @.k; #.j= #.k; @.k= @; #.k= #
if h>=j then leave; j= j - h; k= k - h
end /*while #.k<···*/
end /*i*/ /*hard swaps needed for embedded blanks.*/
end /*while h>1*/; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
get: langs= 0; call rdr 'languages' /*assign languages ───► L.ααα */
call rdr 'categories' /*append categories ───► catHeap */
#= 0
do j=1 until catHeap=='' /*process the heap of categories. */
parse var catHeap cat.j (sep) catHeap /*get a category from the catHeap. */
parse var cat.j cat.j '<' "(" mems . /*untangle the strange─looking string. */
cat.j= space(cat.j); ?=cat.j; upper ? /*remove any superfluous blanks. */
if ?=='' | \L.? then iterate /*it's blank or it's not a language. */
if pos(',', mems)\==0 then mems= space(translate(mems,,","), 0) /*¬commas.*/
if \datatype(mems, 'W') then iterate /*is the "members" number not numeric? */
#.0= #.0 + mems /*bump the number of members found. */
if u.?\==0 then do; do f=1 for # until ?==@u.f
end /*f*/
#.f= #.f + mems; iterate j /*languages in different cases.*/
end /* [↑] handle any possible duplicates.*/
u.?= u.? + 1; #= # + 1 /*bump a couple of counters. */
#.#= #.# + mems; @.#= cat.j; @u.#=? /*bump the counter; assign it (upper).*/
end /*j*/
!.=; @tno= '(total) number of' /*array holds indication of TIED langs.*/
call tell right(commas(#), 9) @tno 'languages detected in the category file'
call tell right(commas(langs),9) ' " " " " " " " language "
call tell right(commas(#.0), 9) @tno 'entries (solutions) detected', , 1; term= 0
return /*don't show any more msgs──►term. [↑] */
/*──────────────────────────────────────────────────────────────────────────────────────*/
init: sep= '█'; L.=0; #.=0; u.=#.; catHeap=; term=1; old.= /*assign some REXX vars*/
if catFID=='' then catFID= "RC_POP.CAT" /*Not specified? Then use the default.*/
if lanFID=='' then lanFID= "RC_POP.LAN" /* " " " " " " */
if outFID=='' then outFID= "RC_POP.OUT" /* " " " " " " */
call tell center('timestamp: ' date() time("Civil"),79,'═'), 2, 1; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
out: w= length( commas(#) ); rank= 0 /* [↓] show by ascending rank of lang.*/
do t=# by -1 for #; rank= rank + 1 /*bump rank of a programming language. */
call tell right('rank:' right(commas(!tR.t), w), 20-1) right(!.t, 7),
right('('commas(#.t) left("entr"s(#.t, 'ies', "y")')', 9), 20) @.t
end /*#*/ /* [↑] S(···) pluralizes a word. */
call tell left('', 27) "☼ end─of─list. ☼", 1, 2; return /*bottom title.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
rdr: arg which 2; igAst= 1 /*ARG uppers WHICH, obtain the 1st char*/
if which=='L' then inFID= lanFID /*use this fileID for the languages. */
if which=='C' then inFID= catFID /* " " " " " categories. */
Uyir= 'உயிர்/Uyir' /*Unicode (in text) name for Uyir */
old.0= '╬£C++' ; new.0= "µC++" /*Unicode ╬£C++ ───► ASCII─8: µC++ */
old.1= 'UC++' ; new.1= "µC++" /*old UC++ ───► ASCII─8: µC++ */
old.2= '╨£╨Ü-' ; new.2= "MK-" /*Unicode ╨£╨Ü─ ───► ASCII-8: MK- */
old.3= 'D├⌐j├á' ; new.3= "Déjà" /*Unicode ├⌐j├á ───► ASCII─8: Déjà */
old.4= 'Cach├⌐' ; new.4= "Caché" /*Unicode Cach├⌐ ───► ASCII─8: Caché */
old.5= '??-61/52' ; new.5= "MK-61/52" /*somewhere past, a mis─translated: MK-*/
old.6= 'F┼ìrmul├ª' ; new.6= 'Fôrmulæ' /*Unicode ───► ASCII─8: Fôrmulæ */
old.7= '╨£iniZinc' ; new.7= 'MiniZinc' /*Unicode ───► ASCII─8: MiniZinc*/
old.8= Uyir ; new.8= 'Uyir' /*Unicode ───► ASCII─8: Uyir */
old.9= 'Perl 6' ; new.9= 'Raku' /* (old name) ───► (new name) */
do recs=0 while lines(inFID) \== 0 /*read a file, a single line at a time.*/
$= translate( linein(inFID), , '9'x) /*handle any stray TAB ('09'x) chars.*/
$$= space($); if $$=='' then iterate /*ignore all blank lines in the file(s)*/
do v=0 while old.v \== '' /*translate Unicode variations of langs*/
if pos(old.v, $$) \==0 then $$= changestr(old.v, $$, new.v)
end /*v*/ /* [↑] handle different lang spellings*/
if igAst then do; igAst= pos(' * ', $)==0; if igAst then iterate; end
if pos('RETRIEVED FROM', translate($$))\==0 then leave /*pseudo End─Of─Data?.*/
if which=='L' then do; if left($$, 1)\=="*" then iterate /*lang ¬legitimate?*/
parse upper var $$ '*' $$ "<"; $$= space($$)
if $$=='' then iterate; L.$$= 1
langs= langs + 1 /*bump number of languages found. */
iterate
end /* [↓] extract computer language name.*/
if left($$, 1)=='*' then $$= sep || space( substr($$, 2) )
catHeap= catHeap $$ /*append to the catHeap (CATegory) heap*/
end /*recs*/
call tell right( commas(recs), 9) 'records read from file: ' inFID
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell: do '0'arg(2); call lineout outFID," " ; if term then say ; end
call lineout outFID,arg(1) ; if term then say arg(1)
do '0'arg(3); call lineout outFID," " ; if term then say ; end
return /*show BEFORE blank lines (if any), message, show AFTER blank lines.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
tSort: tied=; r= 0 /*add true rank (tR) ───► the entries. */
do j=# by -1 for #; r= r+1; tR= r; !tR.j= r; jp= j+1; jm= j-1
if tied=='' then pR= r; tied= /*handle when language rank is untied. */
if #.j==#.jp | #.j==#.jm then do; !.j= '[tied]'; tied= !.j; end
if #.j==#.jp then do; tR= pR; !tR.j= pR; end
else pR= r
end /*j*/; return
all ranked 813 languages
The output for this REXX (RC_POP.REX) program is included here ──► RC_POP.OUT.
[See the talk page about some programming languages using different cases (lower/upper/mixed) for the language names,
as well as those that use Unicode characters in the name.]
Ring
# Project: Rosetta Code/Rank languages by popularity
load "stdlib.ring"
ros= download("http://rosettacode.org/wiki/Category:Programming_Languages")
pos = 1
totalros = 0
rosname = ""
rosnameold = ""
rostitle = ""
roslist = []
for n = 1 to len(ros)
nr = searchstring(ros,'<li><a href="/wiki/',pos)
if nr = 0
exit
else
pos = nr + 1
ok
nr = searchname(nr)
nr = searchtitle(nr)
next
roslist = sortfirst(roslist)
roslist = reverse(roslist)
see nl
for n = 1 to len(roslist)
see "rank: " + n + " (" + roslist[n][1] + " entries) " + roslist[n][2] + nl
next
func searchstring(str,substr,n)
newstr=right(str,len(str)-n+1)
nr = substr(newstr, substr)
if nr = 0
return 0
else
return n + nr -1
ok
func count(cstring,dstring)
sum = 0
while substr(cstring,dstring) > 0
sum = sum + 1
cstring = substr(cstring,substr(cstring,dstring)+len(string(sum)))
end
return sum
func searchname(sn)
nr2 = searchstring(ros,"/wiki/Category:",sn)
nr3 = searchstring(ros,"title=",sn)
nr4 = searchstring(ros,'">',sn)
nr5 = searchstring(ros,"</a></li>",sn)
rosname = substr(ros,nr2+15,nr3-nr2-17)
rosnameold = substr(ros,nr4+2,nr5-nr4-2)
return sn
func searchtitle(sn)
rostitle = "rosettacode.org/wiki/Category:" + rosname
rostitle = download(rostitle)
nr2 = 0
roscount = count(rostitle,"The following")
if roscount > 0
rp = 1
for rc = 1 to roscount
nr2 = searchstring(rostitle,"The following",rp)
rp = nr2 + 1
next
ok
nr3 = searchstring(rostitle,"pages are in this category",nr2)
if nr2 > 0 and nr3 > 0
rosnr = substr(rostitle,nr2+14,nr3-nr2-15)
rosnr = substr(rosnr,",","")
add(roslist,[rosnr,rosnameold])
ok
return sn
func sortfirst(alist)
for n = 1 to len(alist) - 1
for m = n + 1 to len(alist)
if alist[m][1] < alist[n][1]
swap(alist,m,n)
ok
if alist[m][1] = alist[n][1] and strcmp(alist[m][2],alist[n][2]) > 0
swap(alist,m,n)
ok
next
next
return alist
Output:
rank: 1 (1010 entries) Kotlin rank: 2 (977 entries) Racket rank: 3 (968 entries) Python rank: 4 (962 entries) Perl 6 rank: 5 (931 entries) Go rank: 6 (914 entries) Tcl rank: 7 (905 entries) C rank: 8 (888 entries) J rank: 9 (882 entries) Zkl rank: 10 (875 entries) Java ...... rank: 30 (580 entries) Ring ...... rank: 523 (2 entries) TechBASIC rank: 524 (2 entries) Thyrd rank: 525 (2 entries) ToffeeScript rank: 526 (2 entries) Viua VM assembly rank: 527 (2 entries) XL rank: 528 (2 entries) XProc rank: 529 (2 entries) XSLT 1.0 rank: 530 (2 entries) XTalk rank: 531 (2 entries) XUL rank: 532 (2 entries) ZPL
Ruby
By using the API
Now that there are more than 500 categories, the URL given in the task description is insufficient. I use the RC API to grab the categories, and then count the members of each category.
Uses the RosettaCode
module from Count programming examples#Ruby
require 'rosettacode'
langs = []
RosettaCode.category_members("Programming Languages") {|lang| langs << lang}
# API has trouble with long titles= values.
# To prevent skipping languages, use short slices of 20 titles.
langcount = {}
langs.each_slice(20) do |sublist|
url = RosettaCode.get_api_url({
"action" => "query",
"prop" => "categoryinfo",
"format" => "xml",
"titles" => sublist.join("|"),
})
doc = REXML::Document.new open(url)
REXML::XPath.each(doc, "//page") do |page|
lang = page.attribute("title").value
info = REXML::XPath.first(page, "categoryinfo")
langcount[lang] = info.nil? ? 0 : info.attribute("pages").value.to_i
end
end
puts Time.now
puts "There are #{langcount.length} languages"
puts "the top 25:"
langcount.sort_by {|key,val| val}.reverse[0,25].each_with_index do |(lang, count), i|
puts "#{i+1}. #{count} - #{lang.sub(/Category:/, '')}"
end
- Results:
2010-07-08 14:52:46 -0500 There are 306 languages the top 25: 1. 399 - Tcl 2. 370 - Python 3. 352 - Ruby 4. 338 - J 5. 337 - C 6. 333 - PicoLisp 7. 322 - OCaml 8. 322 - Haskell 9. 299 - Perl 10. 299 - AutoHotkey 11. 288 - Common Lisp 12. 280 - Java 13. 275 - Ada 14. 270 - D 15. 267 - Oz 16. 253 - R 17. 252 - PureBasic 18. 245 - E 19. 243 - C++ 20. 241 - C sharp 21. 239 - ALGOL 68 22. 236 - JavaScript 23. 221 - Forth 24. 207 - Clojure 25. 201 - Fortran
Run BASIC
sqliteconnect #mem, ":memory:" ' make memory DB
#mem execute("CREATE TABLE stats(lang,cnt)")
a$ = httpGet$("http://rosettacode.org/wiki/Category:Programming_Languages")
aa$ = httpGet$("http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000")
i = instr(a$,"/wiki/Category:")
while i > 0 and lang$ <> "Languages"
j = instr(a$,"""",i)
lang$ = mid$(a$,i+15,j - i-15)
ii = instr(aa$,"Category:";lang$;"""")
jj = instr(aa$,"(",ii)
kk = instr(aa$," ",jj+1)
if ii = 0 then cnt = 0 else cnt = val(mid$(aa$,jj+1,kk-jj))
k = instr(lang$,"%") ' convert hex values to characters
while k > 0
lang$ = left$(lang$,k-1) + chr$(hexdec(mid$(lang$,k+1,2))) + mid$(lang$,k+3)
k = instr(lang$,"%")
wend
#mem execute("insert into stats values ('";lang$;"',";cnt;")")
i = instr(a$,"/wiki/Category:",i+10)
wend
html "<table border=2>"
#mem execute("SELECT * FROM stats ORDER BY cnt desc") ' order list by count descending
WHILE #mem hasanswer()
#row = #mem #nextrow()
rank = rank + 1
html "<TR><TD align=right>";rank;"</td><td>";#row lang$();"</td><td align=right>";#row cnt();"</td></tr>"
WEND
html "</table>"
1 | Tcl | 687 |
2 | Python | 650 |
3 | C | 638 |
4 | PicoLisp | 626 |
5 | J | 619 |
6 | Go | 587 |
7 | Ruby | 581 |
8 | D | 571 |
9 | Ada | 559 |
10 | Mathematica | 551 |
11 | Perl | 528 |
12 | Perl_6 | 528 |
13 | Haskell | 526 |
14 | BBC_BASIC | 513 |
15 | REXX | 491 |
16 | Java | 488 |
17 | OCaml | 477 |
18 | PureBasic | 469 |
19 | Unicon | 462 |
20 | AutoHotkey | 430 |
21 | Icon | 429 |
22 | Common_Lisp | 424 |
23 | C_sharp | 416 |
24 | C++ | 400 |
25 | JavaScript | 359 |
26 | Scala | 339 |
27 | PARI/GP | 338 |
28 | Clojure | 335 |
29 | R | 322 |
n | ... | ... |
Scala
Parallel internet querying
Entry point @ object GhettoParserPar
import akka.actor.{Actor, ActorSystem, Props}
import scala.collection.immutable.TreeSet
import scala.xml.XML
// Reports a list with all languages recorded in the Wiki
private object Acquisition {
val (endPoint, prefix) = ("http://rosettacode.org/mw/api.php", "Category:")
val (maxPlaces, correction) = (50, 2)
def convertPathArgsToURL(endPoint: String, pathArgs: Map[String, String]) = {
pathArgs.map(argPair => argPair._1 + "=" + argPair._2)
.mkString(endPoint + (if (pathArgs.nonEmpty) "?" else ""), "&", "")
}
/* The categories include a page for the language and a count of the pages
* linked therein, this count is the data we need to scrape.
* Reports a list with language, count pair recorded in the Wiki
* All strings starts with the prefixes "Category:"
*/
def mineCatos = {
val endPoint = "http://rosettacode.org/mw/index.php"
Concurrent.logInfo("Acquisition of categories started.")
val categories =
(XML.load(convertPathArgsToURL(endPoint,
Map("title" -> "Special:Categories", "limit" -> "5000"))) \\ "ul" \ "li")
.withFilter(p => (p \ "a" \ "@title").text.startsWith(prefix))
.map // Create a tuple pair, eg. ("Category:Erlang", 195)
{ cat =>
((cat \ "a" \ "@title").text, // Takes the sibling of "a" and extracts the number
"[0-9]+".r.findFirstIn(cat.child.drop(1).text).getOrElse("0").toInt)
}
Concurrent.logInfo(s"Got ${categories.size} categories..")
categories
}
// The languages
// All strings starts with the prefixes "Category:"
def mineLangs = {
Concurrent.logInfo("Acquisition of languages started...")
def getLangs(first: Boolean = true, continue: String = ""): TreeSet[String] = (first, continue) match {
case (false, "") => TreeSet[String]()
case _ => {
val xml = XML.load(convertPathArgsToURL(endPoint, Map(
"action" -> "query",
"list" -> "categorymembers",
"cmtitle" -> (prefix + "Programming_Languages"),
"cmlimit" -> "500",
"rawcontinue" -> "",
"format" -> "xml",
"cmcontinue" -> continue)))
getLangs(false, (xml \\ "query-continue" \ "categorymembers" \ "@cmcontinue").text) ++ (xml \\ "categorymembers" \ "cm").map(c => (c \ "@title").text)
}
}
val languages = getLangs()
Concurrent.logInfo(s"Got ${languages.size} languages..")
languages
}
def joinRosettaCodeWithLanguage(catos: Seq[(String, Int)],
langs: TreeSet[String]) =
for {
cato <- catos //Clean up the tuple pairs, eg ("Category:Erlang", 195) becomes ("Erlang", 192)
if langs.contains(cato._1)
} yield (cato._1.drop(prefix.length), cato._2 - correction max 0) // Correct count
def printScrape(languages: TreeSet[String], category: Seq[(String, Int)]) {
val join = joinRosettaCodeWithLanguage(category, languages)
val total = join.foldLeft(0)(_ + _._2)
Concurrent.logInfo("Data processed")
println(f"\nTop$maxPlaces%3d Rosetta Code Languages by Popularity as ${new java.util.Date}%tF:\n")
(join.groupBy(_._2).toSeq.sortBy(-_._1).take(maxPlaces) :+ (0, Seq(("...", 0))))
.zipWithIndex // Group the ex aequo
.foreach {
case ((score, langs), rank) =>
println(f"${rank + 1}%2d. $score%3d - ${langs.map(_._1).mkString(", ")}")
}
println(s"\nCross section yields ${join.size} languages, total of $total solutions")
println(s"Resulting average is ${total / join.size} solutions per language")
}
def printScrape(): Unit = printScrape(mineLangs, mineCatos)
} // object Acquisition
private object Concurrent extends AppCommons {
var (category: Option[Seq[(String, Int)]], language: Option[TreeSet[String]]) = (None, None)
class Worker extends Actor {
def receive = {
case 'Catalogue => sender ! Acquisition.mineCatos
case 'Language => sender ! Acquisition.mineLangs
}
}
class Listener extends Actor {
// Create and signal the worker actors
context.actorOf(Props[Worker], "worker0") ! 'Catalogue
context.actorOf(Props[Worker], "worker1") ! 'Language
def printCompleteScape() =
if (category.isDefined && language.isDefined) {
Acquisition.printScrape(language.get, category.get)
context.system.shutdown()
appEnd()
}
def receive = {
case content: TreeSet[String] =>
language = Some(content)
printCompleteScape()
case content: Seq[(String, Int)] =>
category = Some(content)
printCompleteScape()
case whatever => logInfo(whatever.toString)
} // def receive
}
} // object Concurrent
trait AppCommons {
val execStart = System.currentTimeMillis()
System.setProperty("http.agent", "*")
def logInfo(info: String) {
println(f"[Info][${System.currentTimeMillis() - execStart}%5d ms]" + info)
}
def appEnd() { logInfo("Run succesfully completed") }
}
// Main entry for sequential version (slower)
object GhettoParserSeq extends App with AppCommons {
Concurrent.logInfo("Sequential version started")
Acquisition.printScrape()
appEnd()
}
// Entry for parallel version (faster)
object GhettoParserPar extends App {
Concurrent.logInfo("Parallel version started")
ActorSystem("Main").actorOf(Props[Concurrent.Listener])
}
Sequential internet querying
The same code above but as entry point object GhettoParserSeq
- Output for both solutions:
but parallel run chosen. Notice the synchronous start time.
[Info][ 0 ms]Sequential version started [Info][ 3 ms]Acquisition of languages started... [Info][ 1458 ms]Got 642 languages.. [Info][ 1458 ms]Acquisition of categories started. [Info][19385 ms]Got 2647 categories.. [Info][19389 ms]Data processed Top 50 Rosetta Code Languages by Popularity as 2016-11-11: 1. 907 - Racket 2. 896 - Python, Tcl 3. 859 - J 4. 846 - Perl 6 5. 810 - Ruby 6. 807 - Zkl 7. 795 - C 8. 774 - Java 9. 773 - Go 10. 754 - Haskell 11. 753 - Perl 12. 751 - REXX 13. 750 - D 14. 729 - PicoLisp 15. 689 - Mathematica 16. 674 - Sidef 17. 634 - C++ 18. 631 - Ada 19. 609 - AutoHotkey 20. 592 - Common Lisp 21. 583 - Unicon 22. 569 - Scala 23. 560 - C sharp 24. 546 - BBC BASIC 25. 526 - Icon 26. 522 - Clojure 27. 520 - JavaScript 28. 519 - OCaml 29. 517 - PureBasic 30. 513 - PARI/GP 31. 510 - Lua 32. 509 - Nim 33. 497 - ALGOL 68 34. 491 - Elixir 35. 488 - Fortran 36. 474 - Erlang 37. 430 - PowerShell 38. 428 - Julia 39. 414 - Jq 40. 413 - F Sharp 41. 409 - Phix 42. 407 - Pascal 43. 405 - Forth, Seed7 44. 398 - PL/I 45. 383 - R 46. 382 - PHP 47. 377 - Groovy 48. 370 - AWK 49. 340 - MATLAB 50. 333 - Liberty BASIC 51. 0 - ... Cross section yields 619 languages, total of 50835 solutions Resulting average is 82 solutions per language [Info][19413 ms]Run succesfully completed
Seed7
$ include "seed7_05.s7i";
include "gethttp.s7i";
include "scanstri.s7i";
const type: popularityHash is hash [string] integer;
const type: rankingHash is hash [integer] array string;
const func array string: getLangs (in string: buffer) is func
result
var array string: langs is 0 times "";
local
var integer: pos is 0;
begin
pos := pos(buffer, "Category:");
while pos <> 0 do
pos +:= 9;
langs &:= buffer[pos .. pred(pos(buffer, '"', pos))];
pos := pos(buffer, "Category:", pos);
end while;
end func;
const proc: main is func
local
var string: categories is "";
var popularityHash: popularity is popularityHash.value;
var rankingHash: ranking is rankingHash.value;
var array integer: numList is 0 times 0;
var string: lang is "";
var integer: pos is 0;
var string: numStri is "";
var integer: listIdx is 0;
var integer: index is 0;
var integer: place is 1;
begin
categories := getHttp("www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000");
for lang range getLangs(getHttp("rosettacode.org/mw/api.php?action=query&list=categorymembers&\
\cmtitle=Category:Programming_Languages&cmlimit=500&format=json")) do
pos := pos(categories, "title=\"Category:" & lang);
if pos <> 0 then
pos := pos(categories, "</a>", succ(pos));
if pos <> 0 then
pos := pos(categories, "(", succ(pos));
if pos <> 0 then
numStri := categories[succ(pos) len 10];
popularity @:= [lang] integer parse getDigits(numStri);
end if;
end if;
end if;
end for;
ranking := flip(popularity);
numList := sort(keys(ranking));
for listIdx range maxIdx(numList) downto minIdx(numList) do
for key index range ranking[numList[listIdx]] do
writeln(place lpad 3 <& ". " <& numList[listIdx] <& " - " <& ranking[numList[listIdx]][index]);
end for;
place +:= length(ranking[numList[listIdx]]);
end for;
end func;
List of languages as of 2014-01-15:
1. 772 - Tcl 2. 733 - Racket 3. 718 - Python 4. 685 - C 5. 657 - Perl 6 6. 654 - J 7. 645 - D 8. 643 - Ruby 9. 636 - PicoLisp 10. 624 - Go 11. 610 - Perl 12. 579 - REXX 13. 578 - Ada 14. 567 - Mathematica 14. 567 - Haskell 16. 532 - Unicon 17. 526 - Java 18. 523 - BBC BASIC 19. 489 - OCaml 20. 487 - Icon 21. 477 - C++ 22. 470 - PureBasic 23. 448 - Common Lisp 24. 439 - Erlang 24. 439 - C sharp 26. 437 - AutoHotkey 27. 406 - Scala 28. 382 - JavaScript 29. 375 - Clojure 30. 356 - Seed7 ...
Sidef
require('MediaWiki::API')
var api = %O<MediaWiki::API>.new(
Hash(api_url => 'http://rosettacode.org/mw/api.php')
)
var languages = []
var gcmcontinue
loop {
var apih = api.api(
Hash(
action => 'query',
generator => 'categorymembers',
gcmtitle => 'Category:Programming Languages',
gcmlimit => 250,
prop => 'categoryinfo',
gcmcontinue => gcmcontinue,
)
)
languages.append(apih{:query}{:pages}.values...)
gcmcontinue = apih{:continue}{:gcmcontinue}
gcmcontinue || break
}
languages.each { |lang|
lang{:title} -= /^Category:/
lang{:categoryinfo}{:size} := 0
}
var sorted_languages = languages.sort_by { |lang|
-lang{:categoryinfo}{:size}
}
sorted_languages.each_kv { |i, lang|
printf("%3d. %20s - %3d\n", i+1, lang{:title}, lang{:categoryinfo}{:size})
}
- Output:
1. Racket - 938 2. Python - 930 3. Tcl - 904 4. Perl 6 - 877 5. J - 863 6. Zkl - 834 7. Ruby - 830 8. C - 805 9. Go - 793 10. Haskell - 785 11. Java - 783 12. REXX - 776 13. Perl - 765 14. D - 753 15. PicoLisp - 731 16. Mathematica - 702 17. Sidef - 696 ...
SNOBOL4
-include "url.sno"
http.recl = "K,32767" ;* Read next 32767 characters
;* of very long lines.
rclangs = "http://rosettacode.org/mw/api.php?"
+ "format=xml&action=query&generator=categorymembers&"
+ "gcmtitle=Category:Programming%20Languages&"
+ "gcmlimit=500&prop=categoryinfo"
languagepat = arb "<page" arb 'title="Category:'
+ break('"') . lang arb 'pages="' break('"') . count
langtable = table(500, 20)
url.open(.fin, rclangs, http.recl) :s(read)
output = "Cannot open rosettacode site." :(end)
read line = line fin :f(done)
get line languagepat = :f(read)
langtable<syntaxhighlight lang="text"> = langtable<syntaxhighlight lang="text"> + count :(get)
done langarray = rsort(langtable,2) :s(write)
output = "No languages found." :(end)
write n = n + 1
output = lpad(n ". ", 5) lpad(langarray<n, 2>, 4)
+ " - " langarray<n,1> :s(write)
url.close(.fin)
end
Abridged output (top 30 languages as of August 25, 2015):
1. 875 - Racket 2. 837 - Python 3. 799 - J 4. 772 - Ruby 5. 763 - Perl 6 6. 756 - C 7. 742 - Go 8. 737 - D 9. 707 - Perl 10. 699 - REXX 11. 689 - PicoLisp 12. 683 - Haskell 13. 672 - Mathematica 14. 650 - Java 15. 620 - Ada 16. 588 - AutoHotkey 17. 563 - C++ 18. 553 - Common Lisp 19. 546 - Scala 20. 529 - BBC BASIC 21. 520 - Icon 22. 513 - C sharp 23. 505 - OCaml 24. 501 - Nim 25. 487 - PureBasic 26. 485 - Clojure 27. 455 - Epigram 28. 443 - PARI/GP 29. 431 - JavaScript 30. 410 - Jq
Stata
First we build the database:
copy "http://rosettacode.org/wiki/Category:Programming_Languages" lang.html, replace
import delimited lang.html, delim("@") enc("utf-8") clear
keep if ustrpos(v1,"/wiki/Category:")
gen i = ustrpos(v1,"title=")
gen j = ustrpos(v1,char(34),i+1)
gen k = ustrpos(v1,char(34),j+1)
gen s = usubstr(v1,j,k-j+1)
keep if usubstr(s,2,9)=="Category:"
gen lang=usubstr(s,11,ustrlen(s)-11)
keep lang
save lang, replace
copy "http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000" categ.html, replace
import delimited categ.html, delim("@") enc("utf-8") clear
keep if ustrpos(v1,"/wiki/Category:") & ustrpos(v1,"member")
gen i = ustrpos(v1,"title=")
gen j = ustrpos(v1,char(34),i+1)
gen k = ustrpos(v1,char(34),j+1)
gen s = usubstr(v1,j,k-j+1)
keep if usubstr(s,2,9)=="Category:"
gen lang=usubstr(s,11,ustrlen(s)-11)
drop i j k s
gen i = ustrrpos(v1,"(")
gen j = ustrrpos(v1,")")
gen s = usubstr(v1,i,j-i+1)
gen k = ustrpos(s," ")
gen t = usubstr(s,2,k-1)
destring t, gen(count)
drop v1 i j k s t
merge 1:1 lang using lang, keep(2 3) nogen
replace count=0 if missing(count)
gsort -count lang
gen rank=1
replace rank=rank[_n-1]+(count[_n]!=count[_n-1]) in 2/l
save tasks, replace
Now some results, as of 2017-12-03:
* Total number of entries
qui sum n
di r(sum)
57211
* Number of languages
count
671
* Number of languages with at least one entry
count if count
650
* First 10 languages
list in 1/10, noobs
+-----------------------+
| lang count rank |
|-----------------------|
| Racket 961 1 |
| Python 958 2 |
| Perl 6 925 3 |
| Tcl 918 4 |
| J 883 5 |
|-----------------------|
| C 874 6 |
| Kotlin 868 7 |
| Zkl 857 8 |
| Ruby 845 9 |
| Go 828 10 |
+-----------------------+
Tcl
By web scraping
package require Tcl 8.5
package require http
set response [http::geturl http://rosettacode.org/mw/index.php?title=Special:Categories&limit=8000]
array set ignore {
"Basic language learning" 1
"Encyclopedia" 1
"Implementations" 1
"Language Implementations" 1
"Language users" 1
"Maintenance/OmitCategoriesCreated" 1
"Programming Languages" 1
"Programming Tasks" 1
"RCTemplates" 1
"Solutions by Library" 1
"Solutions by Programming Language" 1
"Solutions by Programming Task" 1
"Unimplemented tasks by language" 1
"WikiStubs" 1
"Examples needing attention" 1
"Impl needed" 1
}
# need substring filter
proc filterLang {n} {
return [expr {[string first "User" $n] > 0}]
}
# (sorry the 1 double quote in the regexp kills highlighting)
foreach line [split [http::data $response] \n] {
if {[regexp {title..Category:([^"]+).* \((\d+) members\)} $line -> lang num]} {
if {![info exists ignore($lang)] && ![filterLang $lang]} {
lappend langs [list $num $lang]
}
}
}
foreach entry [lsort -integer -index 0 -decreasing $langs] {
lassign $entry num lang
puts [format "%d. %d - %s" [incr i] $num $lang]
}
- Output on 29 July 2015 (top 20 entries only):
1. 887 - Tcl 2. 877 - Racket 3. 853 - Python 4. 795 - J 5. 775 - Ruby 6. 766 - Perl 6 7. 757 - C 8. 746 - Go 9. 740 - D 10. 710 - Perl 11. 697 - REXX 12. 692 - PicoLisp 13. 682 - Haskell 14. 675 - Mathematica 15. 652 - Java 16. 634 - Zkl 17. 623 - Ada 18. 591 - AutoHotkey 19. 581 - Unicon 20. 562 - C++ ……
By using the API
package require Tcl 8.5
package require http
package require tdom
namespace eval rc {
### Utility function that handles the low-level querying ###
proc rcq {q xp vn b} {
upvar 1 $vn v
dict set q action "query"
# Loop to pick up all results out of a category query
while 1 {
set url "http://rosettacode.org/mw/api.php?[http::formatQuery {*}$q]"
puts -nonewline stderr . ;# Indicate query progress...
set token [http::geturl $url]
set doc [dom parse [http::data $token]]
http::cleanup $token
# Spoon out the DOM nodes that the caller wanted
foreach v [$doc selectNodes $xp] {
uplevel 1 $b
}
# See if we want to go round the loop again
set next [$doc selectNodes "//query-continue/categorymembers"]
if {![llength $next]} break
dict set q cmcontinue [[lindex $next 0] getAttribute "cmcontinue"]
}
}
### API function: Iterate over the members of a category ###
proc members {page varName script} {
upvar 1 $varName var
set query [dict create cmtitle "Category:$page" {*}{
list "categorymembers"
format "xml"
cmlimit "500"
}]
rcq $query "//cm" item {
# Tell the caller's script about the item
set var [$item getAttribute "title"]
uplevel 1 $script
}
}
### API function: Count the members of a list of categories ###
proc count {cats catVar countVar script} {
upvar 1 $catVar cat $countVar count
set query [dict create prop "categoryinfo" format "xml"]
for {set n 0} {$n<[llength $cats]} {incr n 20} { ;# limit fetch to 20 at a time
dict set query titles [join [lrange $cats $n $n+19] |]
rcq $query "//page" item {
# Get title and count
set cat [$item getAttribute "title"]
set info [$item getElementsByTagName "categoryinfo"]
if {[llength $info]} {
set count [[lindex $info 0] getAttribute "pages"]
} else {
set count 0
}
# Let the caller's script figure out what to do with them
uplevel 1 $script
}
}
}
### Assemble the bits into a whole API ###
namespace export members count
namespace ensemble create
}
# Get the list of programming languages
rc members "Programming Languages" lang {
lappend langs $lang
}
puts stderr "" ;# Because of the progress dots...
puts "There are [llength $langs] languages"
# Get the count of solutions for each, stripping "Category:" prefix
rc count $langs l c {
dict set langcounts [regsub {^Category:} $l {}] $c
}
puts stderr "" ;# Because of the progress dots...
# Print the output
puts "Here are the top fifteen:"
set langcounts [lsort -stride 2 -index 1 -integer -decreasing $langcounts]
set i 0
foreach {lang count} $langcounts {
puts [format "%1\$3d. %3\$3d - %2\$s" [incr n] $lang $count]
if {[incr i]>=15} break
}
# --- generate a full report, similar in format to REXX example
proc popreport {langcounts} {
set bycount {}
foreach {lang count} $langcounts {
dict lappend bycount $count $lang
}
set bycount [lsort -stride 2 -integer -decreasing $bycount]
set rank 1
foreach {count langs} $bycount {
set tied [expr {[llength $langs] > 1 ? "\[tied\]" : ""}]
foreach lang $langs {
puts [format {%15s:%4d %-12s %12s %s} rank $rank $tied "($count entries)" $lang]
}
incr rank [llength $langs]
}
}
popreport $langcounts
- Output:
.. There are 582 languages .............................. Here are the top fifteen: 1. 882 - Tcl 2. 874 - Racket 3. 837 - Python 4. 790 - J 5. 772 - Ruby 6. 762 - Perl 6 7. 754 - C 8. 739 - Go 9. 736 - D 10. 706 - Perl 11. 694 - REXX 12. 689 - PicoLisp 13. 679 - Haskell 14. 672 - Mathematica 15. 649 - Java
Full output is included at Rosetta_Code/Rank_languages_by_popularity/Tcl_API_full_output.
TUSCRIPT
$$ MODE TUSCRIPT
remotedata = REQUEST ("http://www.rosettacode.org/mw/index.php?title=Special:Categories&limit=5000")
allmembers=allnames=""
COMPILE
LOOP d=remotedata
IF (d.sw."<li>") THEN
name=EXTRACT (d,":<<a<><%>>:"|,":<</a>>:")
IF (name.eq."Language users") CYCLE
IF (name.sw."Unimplemented tasks") CYCLE
IF (name.sw."Programming") CYCLE
IF (name.sw."Solutions") CYCLE
IF (name.sw."Garbage") CYCLE
IF (name.sw."Typing") CYCLE
IF (name.sw."BASIC LANG") CYCLE
IF (name.ew."USER") CYCLE
IF (name.ew."tasks") CYCLE
IF (name.ew."attention") CYCLE
IF (name.ew."related") CYCLE
IF (name.ct."*omit*") CYCLE
IF (name.ct.":*Categor*:") CYCLE
IF (name.ct.":WikiSTUBS:") CYCLE
IF (name.ct.":Impl needed:") CYCLE
IF (name.ct.":Implementations:") CYCLE
IF (name.ct.":':") name = EXCHANGE (name,":'::")
members = STRINGS (d,":><1<>>/><<> member:")
IF (members!="") THEN
allmembers=APPEND (allmembers,members)
allnames =APPEND (allnames,name)
ENDIF
ENDIF
ENDLOOP
index = DIGIT_INDEX (allmembers)
index = REVERSE (index)
allmembers = INDEX_SORT (allmembers,index)
allnames = INDEX_SORT (allnames, index)
ERROR/STOP CREATE ("list",SEQ-E,-std-)
time=time(),balt=nalt=""
FILE "list" = time
LOOP n, a=allnames,b=allmembers
IF (b==balt) THEN
nr=nalt
ELSE
nalt=nr=n
ENDIF
content=concat (nr,". ",a," --- ",b)
FILE "list" = CONTENT
balt=b
ENDLOOP
ENDCOMPILE
- Output:
2011-01-24 14:05:27 1. Tcl --- 472 member 2. PicoLisp --- 441 member 3. Python --- 432 member 4. J --- 414 member 5. C --- 394 member 6. Ruby --- 385 member 7. PureBasic --- 371 member 8. Haskell --- 369 member 9. Ada --- 364 member 10. OCaml --- 352 member 11. Perl --- 339 member 11. D --- 339 member 13. Java --- 325 member 14. AutoHotkey --- 308 member 15. Common Lisp --- 305 membe 16. C sharp --- 301 member 17. C++ --- 285 member 18. Oz --- 278 member 19. Clojure --- 272 member 20. R --- 266 member 21. ALGOL 68 --- 262 member 22. Perl 6 --- 258 member 23. JavaScript --- 257 member 24. E --- 254 member 25. REXX --- 253 member 26. Fortran --- 251 member 27. Forth --- 248 member 28. Lua --- 238 member 29. PHP --- 215 member 30. Unicon --- 211 member 31. Icon --- 210 member 32. Factor --- 207 member 33. Scala --- 197 member 34. PL/I --- 193 member 34. Go --- 193 member 36. Scheme --- 186 member
UnixPipes
curl 'http://rosettacode.org/mw/index.php?title=Special:Categories&limit=5000' |
sed -nre 's/^<li.*title="Category:([^"(]+)".*\(([0-9]+) members\).*/\2 - \1/p' |
sort -nr | awk '{printf "%2d. %s\n",NR,$0}'
VBScript
Uses the API. Instead of displaying it on the command prompt, the records of the languages are saved on a text file "OutVBRC.txt" encoded with Unicode.
'''''''''''''''''''''''''''''''''''''''''''''
' Rosetta Code/Rank Languages by Popularity '
' VBScript Implementation '
'...........................................'
'API Links (From C Code)
URL1 = "http://www.rosettacode.org/mw/api.php?format=json&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo&rawcontinue"
URL2 = "http://www.rosettacode.org/mw/api.php?format=json&action=query&generator=categorymembers&gcmtitle=Category:Programming%20Languages&gcmlimit=500&prop=categoryinfo&gcmcontinue="
'Get Contents of the API from the Web...
Function ScrapeGoat(link)
On Error Resume Next
ScrapeGoat = ""
Err.Clear
Set objHttp = CreateObject("Msxml2.ServerXMLHTTP")
objHttp.Open "GET", link, False
objHttp.Send
If objHttp.Status = 200 And Err = 0 Then ScrapeGoat = objHttp.ResponseText
Set objHttp = Nothing
End Function
'HACK: Setup HTML for help of my partner/competitor that is better than me, JavaScript...
Set HTML = CreateObject("HtmlFile")
Set HTMLWindow = HTML.ParentWindow
''''''''''''''''''''
' Main code begins '
'..................'
On Error Resume Next
isComplete = 0 ' 1 -> Complete Already
cntLoop = 0 ' Counts Number of Loops Done
Set outputData = CreateObject("Scripting.Dictionary")
Do
'Scrape Data From API
If cntLoop = 0 Then strData = ScrapeGoat(URL1) Else strData = ScrapeGoat(URL2 & gcmCont)
If Len(strData) = 0 Then
Set HTML = Nothing
WScript.StdErr.WriteLine "Processing of data stopped because API query failed."
WScript.Quit(1)
End If
'Parse JSON HACK
HTMLWindow.ExecScript "var json = " & strData, "JavaScript"
Set ObjJS = HTMLWindow.json
Err.Clear 'Test if Query is Complete Already
batchCompl = ObjJS.BatchComplete
If Err.Number = 438 Then
'Query not yet complete. Get gcmContinue instead.
gcmCont = ObjJS.[Query-Continue].CategoryMembers.gcmContinue
Else
isComplete = 1 'Yes!
End If
'HACK #2: Put all language page ids into a JS array to be accessed by VBScript
HTMLWindow.ExecScript "var langs=new Array(); for(var lang in json.query.pages){langs.push(lang);}" & _
"var nums=langs.length;", "JavaScript"
Set arrLangs = HTMLWindow.langs
arrLength = HTMLWindow.nums
For i = 0 to arrLength - 1
BuffStr = "ObjJS.Query.Pages.[" & Eval("arrLangs.[" & i & "]") & "]"
EachStr = Eval(BuffStr & ".title")
Err.Clear
CntLang = Eval(BuffStr & ".CategoryInfo.Pages")
If InStr(EachStr, "Category:") = 1 And Err.Number = 0 Then
outputData.Add Replace(EachStr, "Category:", "", 1, 1), CntLang
End If
Next
cntLoop = cntLoop + 1
Loop While isComplete = 0
'The outputData now contains the data we need. We should now sort and print it!
'Make a 2D array with copy of outputData
arrRelease = Array()
ReDim arrRelease(UBound(outputData.Keys), 1)
outKeys = outputData.Keys
outItem = outputData.Items
For i = 0 To UBound(outKeys)
arrRelease(i, 0) = outKeys(i)
arrRelease(i, 1) = outItem(i)
Next
'Bubble Sort (Greatest to Least Number of Examples)
For i = 0 to UBound(arrRelease, 1)
For j = 0 to UBound(arrRelease, 1) - 1
If arrRelease(j, 1) < arrRelease(j + 1, 1) Then
temp1 = arrRelease(j + 1, 0)
temp2 = arrRelease(j + 1, 1)
arrRelease(j + 1, 0) = arrRelease(j, 0)
arrRelease(j + 1, 1) = arrRelease(j, 1)
arrRelease(j, 0) = temp1
arrRelease(j, 1) = temp2
End If
Next
Next
'Save contents to file instead to support Unicode Names
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set txtOut = objFSO.CreateTextFile(".\OutVBRC.txt", True, True)
txtOut.WriteLine "As of " & Now & ", RC has " & UBound(arrRelease) + 1 & " languages."
txtOut.WriteLine ""
For i = 0 to UBound(arrRelease)
txtOut.WriteLine arrRelease(i, 1) & " Examples - " & arrRelease(i, 0)
Next
'Successfully Done :)
Set HTML = Nothing
Set objFSO = Nothing
WScript.Quit(0)
- Some Parts of Output as of December 31, 2016:
As of 12/31/2016 11:52:05 PM, RC has 624 languages. 917 Examples - Racket 906 Examples - Python 894 Examples - Tcl 859 Examples - J 853 Examples - Perl 6 819 Examples - Zkl 813 Examples - Ruby 796 Examples - C 776 Examples - Java 774 Examples - Go 766 Examples - Haskell 760 Examples - REXX 755 Examples - Perl 750 Examples - D . . . 0 Examples - SheerPower 4GL 0 Examples - Script Basic 0 Examples - VRML 0 Examples - Thistle 0 Examples - UserRPL 0 Examples - WML 0 Examples - VAX Assembly
Visual Basic .NET
Uses Web scrapping to get the information from the Languages category page - as this now shows the number of pages in each category with the non-task pages separated, there is no need to access other pages.
It may be necessary to set the Security Protocol to Tls12 at the start of the Main method in order to run this - see the "Problem running the C# entry" section on the Talk:Rosetta Code/Count examples page.
Imports System.Collections
Imports System.Collections.Generic
Imports System.Net
Imports System.Text.RegularExpressions
Module RankLanguagesByPopularity
Private Class LanguageStat
Public name As String
Public count As Integer
Public Sub New(name As String, count As Integer)
Me.name = name
Me.count = count
End Sub
End Class
Private Function CompareLanguages(x As LanguageStat, y As languageStat) As Integer
Dim result As Integer = 0
If x IsNot Nothing Or y IsNot Nothing Then
If x Is Nothing Then
result = -1
ElseIf y Is Nothing
result = 1
Else
result = - x.count.CompareTo(y.count) ' Sort descending count
If result = 0 Then
result = x.name.CompareTo(y.name) ' Sort ascending name
End If
End If
End If
Return result
End Function
Public Sub Main(ByVal args As String())
Dim languages As New List(Of LanguageStat)
Dim basePage As String = "https://rosettacode.org/wiki/Category:Programming_Languages"
Dim nextPage As String = basePage
Dim nextPageEx = New RegEx("<a href=""/wiki/Category:Programming_Languages([?]subcatfrom=[^""]*)""")
Dim languageStatEx = _
New Regex(">([^<]+?)</a>[^<]*<span title=""Contains *[0-9,.]* *[a-z]*, *([0-9,.]*) *page")
Do While nextPage <> ""
Dim wc As New WebClient()
Dim page As String = wc.DownloadString(nextPage)
nextPage = ""
For Each link In nextPageEx.Matches(page)
nextPage = basePage & link.Groups(1).Value
Next link
For Each language In languageStatEx.Matches(page)
Dim lCount As Integer = 0
Dim lName As String = language.Groups(1).Value
Dim countText As String = language.Groups(2).Value.Replace(",", "").Replace(".", "")
If Not Integer.TryParse(countText, lCount)
Console.Out.WriteLine(lName & "Invalid page count: <<" & countText & ">>")
Else
languages.Add(New LanguageStat(lName, lCount))
End If
Next language
Loop
languages.Sort(AddressOf CompareLanguages)
Dim prevCount As Integer = -1
Dim prevPosition As Integer = -1
Dim position As Integer = 0
For Each stat As LanguageStat In languages
position += 1
If stat.count <> prevCount Then
prevPosition = position
prevCount = stat.Count
End If
Console.Out.WriteLine(prevPosition.ToString.PadLeft(4) & ": " &
stat.count.ToString.PadLeft(4) & " " & stat.name)
Next stat
End Sub
End Module
- Output:
Sample output as at 11th September 2023
1: 1652 Phix 1: 1652 Wren 3: 1614 Julia 4: 1595 Raku 5: 1576 Nim 6: 1546 Go 7: 1531 Perl 8: 1470 Python 9: 1375 J 10: 1285 C . . .
Wren
An embedded program so we can use libcurl.
/* Rosetta_Code_Rank_languages_by_popularity.wren */
import "./pattern" for Pattern
import "./fmt" for Fmt
var CURLOPT_URL = 10002
var CURLOPT_FOLLOWLOCATION = 52
var CURLOPT_WRITEFUNCTION = 20011
var CURLOPT_WRITEDATA = 10001
foreign class Buffer {
construct new() {} // C will allocate buffer of a suitable size
foreign value // returns buffer contents as a string
}
foreign class Curl {
construct easyInit() {}
foreign easySetOpt(opt, param)
foreign easyPerform()
foreign easyCleanup()
}
var curl = Curl.easyInit()
var getContent = Fn.new { |url|
var buffer = Buffer.new()
curl.easySetOpt(CURLOPT_URL, url)
curl.easySetOpt(CURLOPT_FOLLOWLOCATION, 1)
curl.easySetOpt(CURLOPT_WRITEFUNCTION, 0) // write function to be supplied by C
curl.easySetOpt(CURLOPT_WRITEDATA, buffer)
curl.easyPerform()
return buffer.value
}
var p1 = Pattern.new("> <a href/=\"//wiki//Category:+1^\"\" title/=\"Category:[+1^\"]\">+1^,, [+1^ ] page")
var p2 = Pattern.new("subcatfrom/=[+1^#/#mw-subcategories]\"")
var findLangs = Fn.new {
var url = "https://rosettacode.org/w/index.php?title=Category:Programming_Languages"
var subcatfrom = ""
var langs = []
while (true) {
var content = getContent.call(url + subcatfrom)
var matches1 = p1.findAll(content)
for (m in matches1) {
var name = m.capsText[0]
var tasks = Num.fromString(m.capsText[1].replace(",", ""))
langs.add([name, tasks])
}
var m2 = p2.find(content)
if (m2) subcatfrom = "&subcatfrom=%(m2.capsText[0])" else break
}
return langs
}
var langs = findLangs.call()
langs.sort { |a, b| a[1] > b[1] }
System.print("Languages with most examples as at 3 February, 2024:")
var rank = 0
var lastScore = 0
var lastRank = 0
for (i in 0...langs.count) {
var pair = langs[i]
var eq = " "
rank = i + 1
if (lastScore == pair[1]) {
eq = "="
rank = lastRank
} else {
lastScore = pair[1]
lastRank = rank
}
Fmt.print("$-3d$s $-20s $,5d", rank, eq, pair[0], pair[1])
}
We now embed this script in the following C program, build and run.
/* gcc Rosetta_Code_Rank_languages_by_popularity.c -o Rosetta_Code_Rank_languages_by_popularity -lcurl -lwren -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"
struct MemoryStruct {
char *memory;
size_t size;
};
/* C <=> Wren interface functions */
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(!ptr) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
void C_bufferAllocate(WrenVM* vm) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct MemoryStruct));
ms->memory = malloc(1);
ms->size = 0;
}
void C_bufferFinalize(void* data) {
struct MemoryStruct *ms = (struct MemoryStruct *)data;
free(ms->memory);
}
void C_curlAllocate(WrenVM* vm) {
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
*pcurl = curl_easy_init();
}
void C_value(WrenVM* vm) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 0);
wrenSetSlotString(vm, 0, ms->memory);
}
void C_easyPerform(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_perform(curl);
}
void C_easyCleanup(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_cleanup(curl);
}
void C_easySetOpt(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
if (opt < 10000) {
long lparam = (long)wrenGetSlotDouble(vm, 2);
curl_easy_setopt(curl, opt, lparam);
} else if (opt < 20000) {
if (opt == CURLOPT_WRITEDATA) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 2);
curl_easy_setopt(curl, opt, (void *)ms);
} else if (opt == CURLOPT_URL) {
const char *url = wrenGetSlotString(vm, 2);
curl_easy_setopt(curl, opt, url);
}
} else if (opt < 30000) {
if (opt == CURLOPT_WRITEFUNCTION) {
curl_easy_setopt(curl, opt, &WriteMemoryCallback);
}
}
}
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Buffer") == 0) {
methods.allocate = C_bufferAllocate;
methods.finalize = C_bufferFinalize;
} else if (strcmp(className, "Curl") == 0) {
methods.allocate = C_curlAllocate;
}
}
return methods;
}
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Buffer") == 0) {
if (!isStatic && strcmp(signature, "value") == 0) return C_value;
} else if (strcmp(className, "Curl") == 0) {
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform;
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup;
}
}
return NULL;
}
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
config.loadModuleFn = &loadModule;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Rosetta_Code_Rank_languages_by_popularity.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}
- Output:
Showing just the top thirty.
Languages with most examples as at 3 February, 2024: 1 Wren 1,665 1 = Phix 1,665 3 Julia 1,638 4 Raku 1,608 5 Nim 1,576 6 Go 1,547 7 Perl 1,540 8 Python 1,497 9 J 1,413 10 Java 1,318 11 C 1,293 12 C++ 1,258 13 Ruby 1,235 14 Mathematica 1,200 15 FreeBASIC 1,185 16 Haskell 1,166 17 REXX 1,152 18 Kotlin 1,143 19 Racket 1,099 20 Jq 1,081 21 Sidef 1,051 22 11l 1,016 23 Zkl 1,011 24 Factor 1,001 25 D 990 26 ALGOL 68 986 27 Tcl 983 28 Scala 948 29 Delphi 945 30 Ada 940 30 = Rust 940
zkl
Using cURL and YAJL (yet anothe JSON library) libraries.
This solution using the API as the web scraping URL is pretty slow. I'm using JSON as format=txt has been deprecated.
var [const] CURL=Import("zklCurl"), YAJL=Import("zklYAJL")[0];
fcn getLangCounts(language){ // -->( (count,lang), ...)
continueValue,tasks,curl := "",List(), CURL(); // "nm\0nm\0...."
do{ // eg 5 times
page:=curl.get(("http://rosettacode.org/mw/api.php?"
"format=json"
"&action=query"
"&generator=categorymembers"
"&gcmtitle=Category:Programming%%20Languages"
"&gcmlimit=500"
"&prop=categoryinfo"
"&rawcontinue" // remove warning
"&gcmcontinue=%s")
.fmt(continueValue));
page=page[0].del(0,page[1]); // get rid of HTML header
json:=YAJL().write(page).close();
json["query"]["pages"].howza(9).pump(tasks,fcn(d){ #dictionary values,only
// { title:Category:AWK,categoryinfo:{ pages:398,size:401,... },... }
// Gotta take care of no categoryinfo case
count:=d.find("categoryinfo",Dictionary).find("size",0); // or pages?
if(count<300) return(Void.Skip); // prune
T(count,d["title"].del(0,9)); // "Category:RPL" --> "RPL"
});
if(continueValue=json.find("query-continue"))
// subcat|524558580a52455858|4331 or void
continueValue=continueValue["categorymembers"]["gcmcontinue"];
}while(continueValue);
tasks
}
langCounts:=getLangCounts() .sort(fcn(a,b){ a[0]>b[0] }); // reverse sort
println("Most popular Rosetta Code languages as of ",Time.Date.prettyDay());
foreach n,name in ([1..15].zip(langCounts))
{ println("%2d: %3d %s".fmt(n,name.xplode())) }
- Output:
Most popular Rosetta Code languages as of Saturday, the 23rd of September 2017 1: 957 Racket 2: 953 Python 3: 918 Tcl 4: 904 Perl 6 5: 877 J 6: 854 Zkl 7: 840 Ruby 8: 828 C 9: 812 Go 10: 805 Haskell 11: 801 REXX 12: 800 Kotlin 13: 788 Java 14: 776 Perl 15: 755 D
- Networking and Web Interaction
- Sorting
- Rosetta Code related
- Programming Tasks
- Text processing
- Ada
- AWS
- ALGOL 68
- ALGOL 68 examples needing attention
- Examples needing attention
- AutoHotkey
- AWK
- BBC BASIC
- Bracmat
- C
- C examples needing attention
- Libcurl
- C sharp
- C++
- Boost
- Caché ObjectScript
- D
- Delphi
- System.SysUtils
- System.Classes
- IdHttp
- IdBaseComponent
- IdComponent
- IdIOHandler
- IdIOHandlerSocket
- IdIOHandlerStack
- IdSSL
- IdSSLOpenSSL
- System.RegularExpressions
- System.Generics.Collections
- System.Generics.Defaults
- Erlang
- F Sharp
- Go
- Groovy
- Haskell
- HicEst
- Icon
- Unicon
- J
- Java
- Jq
- Julia
- Kotlin
- Lasso
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- Nim
- Objeck
- OoRexx
- PascalABC.NET
- Oz
- OzHttpClient
- Perl
- Phix
- Phix/libcurl
- PicoLisp
- PowerShell
- PureBasic
- Python
- R
- Racket
- Raku
- Red
- REXX
- Ring
- Ruby
- Run BASIC
- Scala
- Seed7
- Sidef
- SNOBOL4
- Stata
- Tcl
- TDOM
- TUSCRIPT
- UnixPipes
- Curl
- VBScript
- Visual Basic .NET
- Wren
- Wren-pattern
- Wren-fmt
- Zkl
- Batch File/Omit
- Brainf***/Omit
- Lilypond/Omit
- Maxima/Omit
- PARI/GP/Omit
- PostScript/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Yorick/Omit
- ZX Spectrum Basic/Omit