15
\$\begingroup\$

Write a program that outputs the contents of the first HTML <code>...</code> block of the answer to this question that is just above yours when the answers are sorted by votes. Output Top! if you are the top answer.

Ignore answers that have negative votes or no <code>...</code> tags. The source of your program must appear in the first <code>...</code> block in your post. These blocks are created automatically when you use backticks or

indent things with 4 spaces.

This is code-golf, the answer with the fewest characters wins.

Additional Rules (Updated)

  • Answer in any programming language you want but if you answer multiple times use different languages.
  • You may not hard code your output. Your program's ability to run correctly should not depend on it's vote count or on what the answer above is. If the vote distribution changed drastically your program should still correctly output the code of the answer above it.
  • You may hard code your program to search for itself on this page (so as to find the next highest) via some unique property of your answer, such as your username (if you only have one answer) or the answer's direct link.
  • If two answers have equal votes you should still use the one just above yours (which I believe will be the newest one).
  • You may have multiple <code>...</code> blocks in your answer but the first one must contain your program's source.
\$\endgroup\$
10
  • 1
    \$\begingroup\$ Do I have to account for multiple pages? \$\endgroup\$
    – Οurous
    Jul 18, 2014 at 3:02
  • 1
    \$\begingroup\$ Yes you should account for multiple pages \$\endgroup\$ Jul 18, 2014 at 3:04
  • 4
    \$\begingroup\$ Note that inline code spans are just <code></code>, but proper code blocks are <pre><code>stuff</code></pre>. \$\endgroup\$
    – Doorknob
    Jul 18, 2014 at 4:03
  • 3
    \$\begingroup\$ @Calvin'sHobbies I think the order of tied answers (by votes) is random. At least on SO, I don't know about here. \$\endgroup\$ Jul 18, 2014 at 11:51
  • 4
    \$\begingroup\$ I would argue that caring about multiple pages is unnecessary - if you aren't on the first page, you aren't WINNING anyway :) \$\endgroup\$
    – lrn
    Jul 18, 2014 at 16:21

11 Answers 11

6
\$\begingroup\$

PHP 666 611 593 588 580 Characters

Edit: Used even smaller url than previously from tinyurl.

Edit: Following comment on other answer I used int rather than boolean. Also needed to correct an error that became apparent but fixed now.

Here is my code

<?
$a=34727;$b=new DOMDocument();$b->loadHTMLFile("http://turl.no/t2u");$c=$b->saveHTML();$d=$e=1;$f='data-answerid="';$g=strpos($c,$f);$h=substr($c,0,$g);$c=substr($c,($g+15));while($d==1){$g=strpos($c,'"');$i=substr($c,0,$g);if($i==$a){$j=$h;$k=$e;}$g=strpos($c,'vote-count-post ">');$c=substr($c,($g+18));$g=strpos($c,'<');$l=substr($c,0,$g);$g=strpos($c,'data-answerid="');if($g){++$e;++$e;$h=substr($c,0,$g);$c=substr($c,($g+15));}else{$d=2;}}if($k==1){echo 'Top!';}else{$g=strpos($j,'><code>');$m=strpos($j,'</code></pre>');$n=$m-$g-7;$o=substr($j,($g+7),$n);echo nl2br($o);}

I am sure this can be improved using DOMXPath and nodes. However am quite pleased with it. I could not decide what to do in the case of mine is the only answer but with -ve points so ignored. However another answer was posted so not a problem any more.

I also used tinyurl to shorten the url, saving lots of characters.

I hope you like it,

Paul.

PS This will not run in codepad so can't show a fiddle.

Edit: saved 5 more with the php tags being altered

You can see it working here on a domain I do not currently use (so am not just trying a sneaky link). This is not a permanent link though but is currently available.

\$\endgroup\$
6
  • \$\begingroup\$ You could shorten it even more by using an even shorter urlshortener=) for example ➡.ws/.v \$\endgroup\$
    – flawr
    Jul 18, 2014 at 16:24
  • \$\begingroup\$ I tried it with the tinyarrows.com link but the delay in connecting times out the server. They are genuinely tiny urls though. \$\endgroup\$ Jul 18, 2014 at 20:49
  • 1
    \$\begingroup\$ On this site, it is acceptable to use a shortened opening tag (I believe it's <? instead of <?php) and leave off the closing tag. That should leave you a few more chars. \$\endgroup\$
    – Justin
    Jul 18, 2014 at 23:40
  • 1
    \$\begingroup\$ turl.no makes some pretty short links, and because it's a Norwegian link shortener, few people have noticed it internationally. Here's a link for you: turl.no/t2u points to the same page as your tinyurl.com link, and saves 8 characters. \$\endgroup\$
    – bilde2910
    Jul 20, 2014 at 22:39
  • \$\begingroup\$ @bilde2910 Thankyou, that worked and it is indeed another very tiny url. Much appreciated and Turl.ca is interesting. He loves his .ca domains doesn't he :-) \$\endgroup\$ Jul 20, 2014 at 23:24
5
\$\begingroup\$

Javascript + jQuery (92 86 64 char)

To test, open Dev Tools on this page (usually F12), and run my code!

This Javscript needs to be run using the console from this page (and only this page).

alert($("code",$("#answer-34767").prev().prev()).html()||"Top!")

So short, it doesn't even need a scrollbar!

Basically, it finds my answer by ID, and then gets two nodes ahead (skipping the anchor link). If that does not exist, I must be on top. Then it digs down to the first code element and gets it's .innerHTML.

The nice thing is that SE uses jQuery by default, so I get that advantage without even trying.

\$\endgroup\$
10
  • 2
    \$\begingroup\$ I personally don't like your answer as it's a bit like cheating... Anyway, it could be as short as alert($("code",$("#answer-34767").prev().prev()).html()||"Top!"). \$\endgroup\$
    – core1024
    Jul 19, 2014 at 8:18
  • \$\begingroup\$ @core1024: Thanks for the improvment! I hadn't thought of doing it one-statement. I agree that I do have a huge advantage. Maybe I have to count Firefox's code for >78MB? The rules say "Answer in any programming language you want". \$\endgroup\$ Jul 19, 2014 at 15:19
  • \$\begingroup\$ You don't need to count the Firefox's code :) Your advantage is in the current environment and not in the interpreter. It's as if everybody had the source of the page already loaded in an "object"/"variable". +1 for the exploit ;) \$\endgroup\$
    – core1024
    Jul 19, 2014 at 18:45
  • 4
    \$\begingroup\$ This is gonna alert "top" if it's top of the second page, is this the correct behavior? \$\endgroup\$ Jul 21, 2014 at 1:29
  • \$\begingroup\$ @WilliamBarbosa: I'm with "lrn" on that one. (see his comment on OP's question). \$\endgroup\$ Jul 21, 2014 at 14:50
4
\$\begingroup\$

Dart 412 403

import"dart:io";import"dart:convert";main(){new HttpClient().get("pi.vu",0,"BYga").then((v)=>v.close()).then((r)=>r.transform(UTF8.decoder).join()).then((s,[i,c="Top!"])=>new RegExp(r'<div id="answer-(\d+)[^]*?vote-count-post ">(\d+)[^]*?<table class="fw"').allMatches(s).forEach((m)=>m[1]=="34735"?print(c):m[2][0]!='-'&&(i=(s=m[0]).indexOf("<code>"))>0?c=s.substring(i+6,s.indexOf("</code>",i)):0));}

Ungolfed (well, with newlines and leading whitespace)

import"dart:io";
import"dart:convert";
main(){
  new HttpClient().get("pi.vu",0,"BYga")
  .then((v)=>v.close())
  .then((r)=>r.transform(UTF8.decoder).join())
  .then((s,[i,c="Top!"])=>
      new RegExp(r'<div id="answer-(\d+)[^]*?vote-count-post ">(\d+)[^]*?<table class="fw"')
      .allMatches(s)
      .forEach((m)=>
          m[1]=="34735"?print(c)
                       :m[2][0]!='-'&&(i=(s=m[0]).indexOf("<code>"))>0
                           ?c=s.substring(i+6,s.indexOf("</code>",i)):0
  ));
}
\$\endgroup\$
0
4
\$\begingroup\$

Delphi (688 873 859 848 840)

I will still try to shave off some characters but it will do the job :)

Edit: instead of getting it shorter I made it longer :P
I forgot to add in the ignoring of answers when it has a negative votecount or no code blocks.

I'm just updating the un-golfed version while editing.
Thanks to @manatwork for the suggested edits that took off 8 characters.

Golfed version:

uses IdHTTP,Classes,MSHTML;const u='http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718#34718';var g:TIdHTTP;m:TMemoryStream;l:TStringList;p,t,r,o:OleVariant;s,i,j:int32;c:boolean;begin L:=TStringList.Create;g:=TIdHTTP.Create(nil);m:=TMemoryStream.Create;g.Get(u,m);m.Position:=0;L.LoadFromStream(m);p:=coHTMLDocument.Create as IHTMLDocument2;p.write(l.Text);for I:=0to p.body.all.length-1do begin c:=0>1;t:=p.body.all.item(i);if(t.classname='answer')and(t.id='answer-34718')then if s=0 then writeln('Top!') else for j:=0to o.all.length-1do begin t:=o.all.item(j);if t.tagname='CODE'then writeln(t.innertext);end else if t.classname='answer'then begin for j:=0to t.all.length-1do begin r:=t.all.item(j);if r.tagname='CODE'then c:=1>0 else if c and(r.class='vote-count-post')and(r.innertext[1]<>'-')then begin o:=t;s:=1;end;end;end;end;end.

Ungolfed version:

uses
  IdHTTP,Classes,MSHTML;
const
  u='http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718';
  a='answer';b='CODE';
var
  g:TIdHTTP;
  m:TMemoryStream;
  l:TStrings;
  p,t,r,o,z:OleVariant;
  s,i,j:int32;
  c:byte;
begin
  L:=TStringList.Create;
  g:=TIdHTTP.Create(nil);
  m:=TMemoryStream.Create;
  g.Get(u,m);
  m.Position:=0;
  L.LoadFromStream(m);
  p:=coHTMLDocument.Create as IHTMLDocument2;
  p.write(l.Text);
  z:=p.body.all;
  for I:=0to z.length-1do
  begin
    c:=0;
    t:=z.item(i);
    if(t.classname=a)and(t.id='answer-34718')then
      if s=0 then
        write('Top!')
      else
        for j:=0to o.all.length-1do
        begin
          t:=o.all.item(j);
          if t.tagname=b then
            write(t.innertext)
        end
    else if t.classname=a then
      for j:=0to t.all.length-1do
      begin
        r:=t.all.item(j);
        if r.tagname=b then
          c:=1
        else if(c=1)and(r.class='vote-count-post')and(r.innertext[1]<>'-')then
        begin
          o:=t;
          s:=1;
        end;
      end;
  end;
end.
\$\endgroup\$
4
  • \$\begingroup\$ http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718#34718 can be changed to http://codegolf.stackexchange.com/q/34718, which would save quite a bit of characters. \$\endgroup\$
    – Doorknob
    Jul 18, 2014 at 10:46
  • \$\begingroup\$ Thanks, sadly I also had to add some since I forgot the part where you have to ignore answers with a negative votecount or no code blocks :/.. doesnt work :( I get a 301 permanently moved \$\endgroup\$
    – Teun Pronk
    Jul 18, 2014 at 10:51
  • \$\begingroup\$ As suggested before, you can declare l as TStrings instead. (But keep the instantiation with TStringList.) \$\endgroup\$
    – manatwork
    Jul 18, 2014 at 11:26
  • \$\begingroup\$ I would try to make c byte instead of boolean. \$\endgroup\$
    – manatwork
    Jul 18, 2014 at 11:29
3
\$\begingroup\$

Python - 280

import os, sys, cgi
os.system('wget http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours.html -q -O a')
b=[ x[:-2] for x in open('a').read().split('code>') if x[-1]=='/']
for i, m in enumerate(b):
    if m == cgi.escape(open(sys.argv[0]).read()):
        print b[i-1]

This is my first codegolf, so I hope this is golf-y enough!

Edit: Thanks for the tips! It's looking a bit golfier now.

\$\endgroup\$
4
  • \$\begingroup\$ Doesn't look bad for a first try! Though you could use an URL shortener for the link and get rid of a few spaces in there (for i,m, m==open,etc). \$\endgroup\$ Jul 18, 2014 at 21:38
  • \$\begingroup\$ @HackerCow I think URL shorteners are generally frowned on, but http://codegolf.stackexchange.com/q/34705/14509 would definitely work. \$\endgroup\$ Jul 19, 2014 at 1:19
  • \$\begingroup\$ @KidElephant I removed a bunch of whitespace from your code. I didn't test it or anything but unless I screwed up it should be (logically) the same program. Note that I removed the shebang, those aren't required here. ix.io/dsz Taking out whitespace can save quite a few bytes :) \$\endgroup\$ Jul 19, 2014 at 1:23
  • \$\begingroup\$ Also, for code golf challenges you are supposed to include a byte count. I'd edit one in for you here but your answer is probably going to change if you use any suggestions so I won't bother. You can find the byte count by running wc -c $filename. If your editor appends a trailing newline to files (it probably does) you can subtract one from that to get your final score. \$\endgroup\$ Jul 19, 2014 at 1:26
2
\$\begingroup\$

Mathematica - 159

First time doing parsing in Mathematica

FirstCase[
 Cases[Import["http://bit.do/JGta1","XMLObject"],
 {__,a_,_,_,_,XMLElement[_, {_, "id""answer-34780",__},_],__}a,∞], 
 XMLElement["code",_,{c_}]c,"Top!",∞]
\$\endgroup\$
2
\$\begingroup\$

Ruby 283+17 = 300

This succeeds regardless how few votes this answer gets and no matter if there's a second (or fifteenth) page of answers or not. It uses the data API.

d=34849
JSON.parse(Net::HTTP.get(URI("http://api.stackexchange.com/2.2/questions/34705/answers?site=codegolf&filter=8G3Ng9T*")))['items'].map{|a|abort$1.gsub(/&.+?;/){|g|g[?a]??&:g[?g]??>:?<}if !d&&a['score']>=0&&/<code>(.*?)<\/code>/m=~a['body']
d=p if a['answer_id']==d}
$><<'Top!'

must be run with ruby -rnet/http -rjson (hence the +17)

ungolfed:

d = 34849 # this answer id
i = JSON.parse(Net::HTTP.get(URI("http://api.stackexchange.com/2.2/questions/34705/answers?site=codegolf&filter=8G3Ng9T*")))['items'] # stackexchange api answers for this question
i.map{ |a|
  # if we've already hit this answer, the score's above 0 and there's code...
  if !d && a['score']>=0 && /<code>(.*?)<\/code>/m=~a['body'] then
    # abort with html-unescaped code
    abort $1.gsub(/&.+?;/){ |g|
      # this turns &amp;, &gt; and &lt; into &, > and <, respectively
      g[?a] ? ?& : g[?g] ? ?> : ?<       
    }
  end
  # if we are at our answer, set d = nil
  if a['answer_id']==d then 
    d = p 
  end
}
# no abort. puts 'Top!'
$><<'Top!'

Changelog

300 removed parens in symbol regex

302 initial commit

\$\endgroup\$
3
  • \$\begingroup\$ You can save some bytes by making your filter unsafe \$\endgroup\$ Jun 16, 2016 at 15:14
  • \$\begingroup\$ @ppperry please explain? \$\endgroup\$ Jun 16, 2016 at 15:16
  • \$\begingroup\$ Using unsafe filters means you want have to manually HTML unescape. See the filter docs \$\endgroup\$ Jun 16, 2016 at 15:19
2
\$\begingroup\$

Python 3, 197 191 186 bytes

import urllib.request as u,gzip,json;p='Top!'
for r in json.loads(gzip.decompress(u.urlopen("https://bit.ly/Ƶ").read()).decode())["items"]:
 if r['answer_id']==82837:exit(p)
 p=r['body']

The rules don't say that I can't use the API and that I can't use a url shortener.

https://bit.ly/Ƶ expands to https://api.stackexchange.com/2.2/questions/34705/answers?order=desc&sort=votes&site=codegolf&filter=withbody&pagesize=100 This only works if it is in the top 100 answers sorted by votes.

\$\endgroup\$
2
  • \$\begingroup\$ -6 if you replace https://tinyurl.com/hdemk76 with http://bit.ly/2hN8TKV \$\endgroup\$ Dec 28, 2016 at 12:23
  • \$\begingroup\$ -5 if you use https://bit.ly/Ƶ \$\endgroup\$
    – Makonede
    Apr 24, 2021 at 2:33
1
\$\begingroup\$

PHP 135

<?
preg_match_all('@(\d+?)"></a.*de>(.*)</c@Us',join('
',file('http://pi.vu/BYga')),$m);echo$m[2][array_search(34786,$m[1])-1]?:'Top!';

Edit: lrn's URL shortener produces the shortest URL :)

The RegEx matches the anchor before each answer (together with the answer ID) and the contents inside the first <code> tag. The U flag triggers the Ungreedy mode and the s flag make . matches new lines (very handful). I'm not worried if this matches something else as the answers are escaped, so nobody can insert the < literal in the page's source.

After I get all the answers in $m[2] and their IDs in $m[1], I just use echo to print the answer above mine, as it's in $m[2][array_search(34786,$m[1])-1], or "Top!", if my answer eventually gets first :)

I like the fact that in PHP the ternary operator can be used as a short-circuit operator ?:

\$\endgroup\$
3
  • \$\begingroup\$ That is amazing. I just tested it but it is showing the code from the one below. I am sure this will be a quick fix but thought I would mention it. Amazing job though, 135 in PHP, I still cannot quite believe it... \$\endgroup\$ Jul 20, 2014 at 23:36
  • 1
    \$\begingroup\$ @PaulDrewett Please look at the order when you open this page in private browsing. It's different from the order when you're logged in. \$\endgroup\$
    – core1024
    Jul 21, 2014 at 5:49
  • \$\begingroup\$ Oh, that is suprising. I wonder why? Sorry to point out an error in error. My bad. I did upvote you though as a useful answer. I still think it is amazing... \$\endgroup\$ Jul 21, 2014 at 9:40
1
\$\begingroup\$

Delphi, 461 bytes, 553 bytes

Now handles multiple pages too!

Golfed:

uses IdHTTP,RegularExpressions;var T,S,O:String;K,V,C:Int32;begin repeat Inc(C);Str(C,S);S:=TIdHTTP.Create.Get('http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours?page='+S);T:=T+S;until Pos('<span class="page-numbers next',S)=0;O:='Top!';for T in TRegEx.Split(T,'<a name="') do begin S:=T;Val(Copy(S,1,Pos('"',S)-1),K,C);if C=1then Continue;Delete(S,1,Pos('post ">',S)+6);Val(Copy(S,1,Pos('<',S)-1),V,C);C:=Pos('<code>',S);if(C=0)or(V<0)then Continue;if K=34844then Break;O:=Copy(S,C+6,Pos('</code>',S)-C-6);end;Write(O)end.

(slightly) Ungolfed:

uses
  IdHTTP,RegularExpressions;
var
  T,S,O:String;
  K,V,C:Int32;
begin
  // download all pages in thread and concat them
  repeat
    Inc(C);
    Str(C,S);
    S:=TIdHTTP.Create.Get('http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours?page='+S);
    T:=T+S;
  until Pos('<span class="page-numbers next',S)=0;
  O:='Top!'; // initialize code string to 'Top!'
  for T in TRegEx.Split(T,'<a name="') do begin
    S:=T;
    Val(Copy(S,1,Pos('"',S)-1),K,C); // try to extract user id
    if C=1then Continue; // if failed, continue loop
    Delete(S,1,Pos('post ">',S)+6); // prepare S for next parse
    Val(Copy(S,1,Pos('<',S)-1),V,C); // try to extract vote count
    C:=Pos('<code>',S); // check if <code> tag exists
    if(C=0)or(V<0)then Continue; // make sure vote count is positive and <code> tag exists
    if K=34844then Break; // if its our answer, break the loop
    O:=Copy(S,C+6,Pos('</code>',S)-C-6); // get string in <code> tag
  end;
  Write(O); // write <code> string
end.

How to run:

app.exe > output.txt
\$\endgroup\$
2
  • \$\begingroup\$ nice, could've done that too instead of using the html units.. shame I didn't think of that :P \$\endgroup\$
    – Teun Pronk
    Jul 21, 2014 at 7:18
  • \$\begingroup\$ Thanks. Also, one of the (if not only) codes that handles multiple pages too. \$\endgroup\$
    – rsrx
    Jul 21, 2014 at 14:42
1
\$\begingroup\$

PHP - 412 - 422 - 416 - 252 - 248:

Still a work in progress, I haven't done anything regarding multiple pages (nor has anyone else?)

I got the 200 character drop by cutting out a lot of extra dom, why search for objects when I can just find their position?

This is also my first code golf! I'm happy to have done it in the 200s and using dom methods. Thanks to comments, I just shaved off 4 more characters.

I wanted to do something like jquery/jscript in regards to traversing the dom, and am still working on slimming this down. Maybe I could get away with searching for "asi" as my user name?

Golf:

<? $d=new DOMDocument;$d->loadHTMLFile("http://bit.do/JGta");$x=new DOMXPath($d);$r=$x->query("//*[@class='answer']");$a=-1;while($f=$r->item(++$a))if(strpos($f->nodeValue,"Asitaka"))echo$x->query(".//pre//code",$r->item($a-1))->item(0)->nodeValue;

Formatted:

    <?php
$d = new DOMDocument();
$d->loadHTMLFile("http://bit.do/JGta");
$x = new DOMXPath($d);
$r = $x->query("//*[@class='answer']");
$a = -1;
while($f = $r->item(++$a))
        if ( stripos($f->nodeValue, "Asitaka")!= 0)
            echo $x->query(".//pre//code",$r->item($a-1))->item(0)->nodeValue;
?>

Cheers

\$\endgroup\$
6
  • \$\begingroup\$ Parentheses in new DOMDocument(), and the closing ?> can be omitted in PHP. \$\endgroup\$
    – jimmy23013
    Jul 19, 2014 at 8:24
  • \$\begingroup\$ Thanks, lost 4 more characters. At the moment, I can't imagine how to make it shorter unless I use different classes, DOM accessors are expensive. \$\endgroup\$
    – Asitaka
    Jul 19, 2014 at 11:53
  • \$\begingroup\$ Save characters by changing your user name! \$\endgroup\$
    – DavidG
    Jul 20, 2014 at 1:59
  • \$\begingroup\$ I think this is cool. I am just trying to learn the query part to DOMXPath but I must admit I am finding it tough. I did try it for this but couldn't quite get it. I tested yours but it seems to be reporting the one two above it, not the one directly above. I am sure it is a quick fix but just thought I would mention it. \$\endgroup\$ Jul 20, 2014 at 23:43
  • \$\begingroup\$ Following this info "Please look at the order when you open this page in private browsing. It's different from the order when you're logged in - core1024" from different answer comment I have to assume the same is happening here too. Sorry for that. \$\endgroup\$ Jul 21, 2014 at 9:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.