Java, 1106 bytes
import java.io.*;import java.util.regex.*;()->{String u="",y="",z="",s,t;float h=0,a,l=0,d;int i=-1,k=-1;Matcher m;Pattern p=null;while(i<=k){try(BufferedReader g=new BufferedReader(new InputStreamReader(new java.net.URL("https://codegolf.stackexchange.com/users"+(k==-1?"?tab=NewUsers&sort=creationdate":"/"+i+"/?tab=topactivity")).openStream()));){while((s=g.readLine())!=null){Integer v=0;if(k==-1&s.contains("users/")&!s.contains("profile-me")){m=p.compile("(?<=users/)(\\d+)").matcher(s);if(m.find()){k=v.parseInt(m.group());break;}}if(s.contains("User")){m=p.compile("(?<=User )(.*)(?= - P)").matcher(s);if(m.find())u=m.group();}if(s.contains("Cast")){m=p.compile("(?<=\\>\\().*(?=\\)\\<)").matcher(s);if(m.find()&&(v=v.parseInt(m.group().replace(",","")))>1000){while(1>0){s=g.readLine();m=p.compile("(\\d*,?\\d+)(?=\\<.*\\>)").matcher(s);if(m.find()){if((t=g.readLine()).contains("up")&&(a=0f+v.parseInt(m.group().replace(",",""))/v)>h){y=""+u;h=a;}if(t.contains("down")){if((d=0f+v.parseInt(m.group().replace(",",""))/v)>l){z=""+u;l=d;}break;}}}}}}}catch(Exception e){}}System.out.print(y+"\n"+z);}
As a full class:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.regex.*;
public class C {
public static void main(String[] args) throws Exception {
String u="", y="", z="", s, t;
float h = 0, a, l = 0, d;
int i = -1, k = -1;
Matcher m;
Pattern p = null;
while (i < k) {
// System.out.println(i);
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL("https://codegolf.stackexchange.com/users" + (k == -1 ? "?tab=NewUsers&sort=creationdate" : "/" + i + "/?tab=topactivity")).openStream()));) {
while ((s = br.readLine()) != null) {
Integer v = 0;
if (k == -1 && s.contains("users/") && !s.contains("profile-me")) {
m = p.compile("(?<=users/)(\\d+)").matcher(s);
if (m.find()) {
k = v.parseInt(m.group());
break;
}
}
if (s.contains("User")) {
m = p.compile("(?<=User )(.*)(?= - P)").matcher(s);
if (m.find())
u = m.group();
}
if (s.contains("Cast")) {
m = p.compile("(?<=\\>\\().*(?=\\)\\<)").matcher(s);
if (m.find() && (v = v.parseInt(m.group().replace(",",""))) > 1000) {
while (true) {
s = br.readLine();
m = p.compile("(\\d*,?\\d+)(?=\\<.*\\>)").matcher(s);
if (m.find()) {
if ((t = br.readLine()).contains("up") && (a = 0f + v.parseInt(m.group().replace(",",""))/v)>h) {
y = ""+u;
h = a;
}
if (t.contains("down")) {
if ((d=0f + v.parseInt(m.group().replace(",",""))/v)>l) {
z = ""+u;
l = d;
}
break;
}
}
}
}
}
}
} catch (Exception e) {}
}
System.out.print(y+"\n"+z);
}
}
One word: Damn.
I mean, I've always wanted to do a challenge like this, but boy was it a doozy.
I didn't use the Stack Exchange API (don't know what it is, where to access it, or how to use it :P), so I basically had to do everything on my own; having the program crawl through each of the nearly 60,000 PPCG users' profile pages for the right data, looking up the HTML scripts and accounting for how the vote totals were laid out differently for different users1, and debugging (which was, perhaps unsurprisingly, a huge pain). And let me just say, this code could probably use some serious optimization. It takes well over two hours for the program to finish running on my machine, though most of the time is probably used opening the connections to the sites.
So here's a quick rundown of how it works:
- Create
String
variables to hold the upvotingest and downvotingest users on PPCG.
- Figure out the total number of active (and deleted/nonexistent) user accounts there are on the site. The program visits https://codegolf.stackexchange.com/users?tab=NewUsers&sort=creationdate and looks for the first user on the page, who happens to be the most recent addition to the community, and as such has the highest ID number. This ID number is set to be the total number of iterations for the loop.
- Start at ID 1 and visit https://codegolf.stackexchange.com/users/#, where the pound symbol represents the ID. Parse the HTML code (with regex͠,̰ nőͣ l͇̪e̐̃s̸͖̚͜͝s̡͍̲̫̋ͯ
) and collect the user's username, vote total, upvote total, and downvote total.
- Check to see if the upvotes to total votes ratio is larger than the current largest ratio, and set the current ratio to the new ratio if necessary. Do the same for the downvotes to total votes ratio, and also set the upvotingest and downvotingest user names when needed.
- Do steps 3 and 4 another (near) 60,000 times, incrementing the ID each time. (This takes care of the event when there is a tie.) If the user doesn't exist, either nothing matches or an Exception is thrown, and move on.
- Print the upvotingest and downvotingest users.
Yes, there are quite a few places where I can shave off a few bytes (especially on the strings where I use the contains
method), but I'll save that for later... maybe.
If you decide to run this program, be prepared to wait a couple hours for it to finish execution.
Here's a screenshot of the output:
In case it's difficult to read, at the bottom it says...
gnat
Peter Taylor
...and the total time it took for the program to finish: a whopping two hours, forty-eight minutes, and twenty-three seconds!
1 The instance on which this occurred had to do with how recently the user voted. If the user voted at least once within the past week or month, two(?) additional stats showing how many times they voted over the past week or month appear on their activity page.