27
\$\begingroup\$

Write a software that prints on stdout the number of answers and the number of comments(visible and collapsed of question and answers) of this question/page.

Your script must run with this page closed when it starts.

Expected example output:

A12C40

Where A stands for Answers and C for Comments.

\$\endgroup\$
12
  • 9
    \$\begingroup\$ Little comment to check something, if you dont mind ;) \$\endgroup\$
    – Teun Pronk
    Feb 7, 2014 at 7:30
  • 1
    \$\begingroup\$ All the comments \$\endgroup\$
    – Fez Vrasta
    Feb 7, 2014 at 7:31
  • 1
    \$\begingroup\$ Does the code have to handle the case when the comments are collapsed when there are too many? And there is also the case when there are too many answers (though I doubt it will get that many). \$\endgroup\$ Feb 7, 2014 at 7:37
  • 4
    \$\begingroup\$ How long until someone writes a program that read the most upvoted answer here, and run it ? :D \$\endgroup\$
    – C4stor
    Feb 7, 2014 at 14:26
  • 12
    \$\begingroup\$ Is this a clever scheme to get the most viewed question through people testing their scripts? \$\endgroup\$
    – Boann
    Feb 7, 2014 at 16:09

14 Answers 14

18
\$\begingroup\$

Perl, 91 96  92 chars

$_=`curl -sL qr.net/_9`;s/<[^>]+nt="(.+)/$c+=$1/ge;say"A",s/<td.*"ans//g,C,$c+s/<tr.*"com//g

Some stuff just to break solutions of others ha ha ha :-P

show 93 more comments

href

nt="99" (ha ha crash @Fez Vrasta)

a ,show 99show 99 ha ha

href href href ha ha haha :-D

jeeez, just broke my own answer! I discovered that one of the above tricks, which I thought does nothing, will start working after this answer is not edited for some time! So your solutions will work only for some time. That's why you had seen +1 more answer in your solutions.. It's a timed bomb! My answer is already prone to it :-) Aaah, found a way how to launch it NOW...

\$\endgroup\$
6
  • \$\begingroup\$ In the interest of breaking a few more scripts that use css selectors, perhaps a <a href="" class="comment>comment link</a> might work? \$\endgroup\$ Feb 7, 2014 at 21:10
  • \$\begingroup\$ Denis unfortunatelly SE will not allow you to display this. You can test on your own answer :) \$\endgroup\$
    – Tomas
    Feb 7, 2014 at 21:20
  • \$\begingroup\$ I check for > so it's not breakable \$\endgroup\$
    – Fez Vrasta
    Feb 8, 2014 at 20:45
  • \$\begingroup\$ @FezVrasta ermm.. not breakable? Then how is it possible than I broke it? ;) \$\endgroup\$
    – Tomas
    Feb 9, 2014 at 11:42
  • \$\begingroup\$ @Tomas good, now I do see a proper output with perl -E. Deleting my comment. Also you can delete your reference to my answer, as you are not broking it any more :) \$\endgroup\$
    – fedorqui
    Feb 9, 2014 at 12:15
9
\$\begingroup\$

XQuery, 169, 160, 165

let$d:=html:parse(fetch:binary('http://qr.net/1_'))return"A"||count($d//*[@class="answer"])||"C"||count($d//*[@class="comment"])+sum($d//*[@class="comments-link"]/b)

More readable (with spaces):

let $d:= html:parse(fetch:binary('http://qr.net/1_'))
return "A" || count($d//*[@class="answer"]) || "C" || count($d//*[@class="comment"]) + sum($d//*[@class="comments-link"]/b)

BaseX was used as XQuery processor.

\$\endgroup\$
4
  • \$\begingroup\$ Would be even shorter (by using the doc() function) if this page would be valid XML... \$\endgroup\$
    – dirkk
    Feb 7, 2014 at 10:58
  • \$\begingroup\$ And this seems to be the first answer ever on code-golf using XQuery... turns out to be quite suitable :) \$\endgroup\$
    – dirkk
    Feb 7, 2014 at 11:00
  • 2
    \$\begingroup\$ on this site I discover a new language every day, this one is quite interesting, thanks. Does it count hidden comments? \$\endgroup\$
    – Fez Vrasta
    Feb 7, 2014 at 11:02
  • \$\begingroup\$ @FezVrasta Yeah, and XQuery isn't even esoteric :) Yes it does, thats what $d//*[@class="comments-link"]/b is for (in the <b> tag the number of hidden comments is shown) \$\endgroup\$
    – dirkk
    Feb 7, 2014 at 11:05
7
\$\begingroup\$

Python 3, 180

import lxml.html as h
s=h.parse('http://qr.net/1_').find('body').cssselect
print('A',len(s('.answer')),'C',len(s('.comment'))+sum(int(e.text)for e in s('.comments-link b')),sep='')

I'm assuming that this question won't have multiple pages of answers.

\$\endgroup\$
7
  • \$\begingroup\$ blender: no luck even with block code :P \$\endgroup\$
    – Fez Vrasta
    Feb 7, 2014 at 9:34
  • \$\begingroup\$ @FezVrasta: I'm getting A13C20. Include an angled bracket in the regex and I think it should be good, as those are escaped. \$\endgroup\$
    – Blender
    Feb 7, 2014 at 9:37
  • \$\begingroup\$ Yes I've already did it. thanks \$\endgroup\$
    – Fez Vrasta
    Feb 7, 2014 at 9:43
  • \$\begingroup\$ Hmmm... "Ignore this stuff" huh? What happens if someone edits that out of the answer, then? \$\endgroup\$
    – Iszi
    Feb 7, 2014 at 19:55
  • \$\begingroup\$ Invalid syntax. ,sep='' \$\endgroup\$
    – Runium
    Feb 8, 2014 at 17:57
6
\$\begingroup\$

BASH + AWK 163, 144, 138, 111, 110, 114, 131, 132, 105

curl -sL http://qr.net/_9|awk -F'[<>]' '/^[\t]*>s/{c+=$4}/<tr.*"c/{++c}/<t.*"a/{++a}END{print "A"a"C"c}'

Which is the same as this, but without redirecting to a file:

curl -sL http://qr.net/_9>f
awk -F'[<>]' '/^[\t]*>s/{c+=$4}/<tr.*"c/{++c}/<t.*"a/{++a}END{print "A"a"C"c}' f

Current output

A16C76

Explanation

curl

Transfer a URL.

  • -s in curl is for silent. And -L to follow redirects.
awk

To parse the file. As some answers had some code to break other answers, the parsing has been changed so that it parses from the beginning of the line (^) to make sure it is not broken.

  • -F'[<>]' set field separators as < or >. This way the text can be parsed properly for the "show XXX more comments".
  • /^[\t]*>show <b>/{c+=$4} on lines containing "spaces....>show", get the 4th field (based on <, > separators) and add the value to the comments counter.
  • /^[ ]*<tr.*s="comm/{++c} on lines containing "spaces...
  • /^<td.*rcell">/{++a} on lines containing "", increment the counter of answers.
  • END{print "A"a"C"c} print the output.
\$\endgroup\$
13
  • \$\begingroup\$ so it does not count the collapsed comments? \$\endgroup\$
    – Fez Vrasta
    Feb 7, 2014 at 12:33
  • \$\begingroup\$ i think you mixed m and f in your code: echo "A$(grep -c 'rcell">' m)C$(grep -c 'mment">' f)" should be echo "A$(grep -c 'rcell">' f)C$(grep -c 'mment">' f)", no? \$\endgroup\$
    – plannapus
    Feb 7, 2014 at 12:35
  • \$\begingroup\$ @plannapus yes, error from copy paste. Solved, thanks! \$\endgroup\$
    – fedorqui
    Feb 7, 2014 at 12:36
  • 1
    \$\begingroup\$ Just tested your code, and it reports "A14C159", which I believe is not quite correct. \$\endgroup\$
    – Abhijit
    Feb 8, 2014 at 9:23
  • 1
    \$\begingroup\$ Well @Abhijit it happens that people keep updating their posts to break the conditions in the rest o f the answers... And I cannot keep updating my answer every time someone update his :D \$\endgroup\$
    – fedorqui
    Feb 8, 2014 at 10:12
5
\$\begingroup\$

PHP which actually works (302 chars)

Unlike all of the other answers so far, this returns the correct answer even when the question spills onto more than one page.

<?function g($a,$b,$i){return json_decode(gzinflate(substr(file_get_contents("http://api.stackexchange.com/2.1/$a/$i/$b?site=codegolf"),10,-8)))->items;}$i=array(20277);foreach(g("questions","answers",20277)as$x)$i[]=$x->answer_id;echo"A".(count($i)-1)."C".count(g("posts","comments",implode(";",$i)));
\$\endgroup\$
8
  • \$\begingroup\$ Your number of comments it correct but at the moment there are only 5 answers but you script says there are 6. Is it counting the question? \$\endgroup\$
    – Felix Eve
    Feb 7, 2014 at 12:27
  • \$\begingroup\$ @FelixEve, I think it's probably counting the deleted answer. (count($i)-1) corrects the count to not include the question. \$\endgroup\$ Feb 7, 2014 at 13:02
  • \$\begingroup\$ @PeterTaylor How can the script see the deleted answer? It should only be in the markup if logged in with a user that has privilege. \$\endgroup\$
    – Cruncher
    Feb 7, 2014 at 18:28
  • \$\begingroup\$ from PHP 5.4 you can use [] instead of array() to initialize \$\endgroup\$
    – Einacio
    Feb 7, 2014 at 19:33
  • \$\begingroup\$ This one won't actually work if there the joined $i has over 100 items. (My own version of the same in ruby doesn't have this limitation. Though admittedly it may bump into API limits. ;-) ) \$\endgroup\$ Feb 7, 2014 at 20:25
5
\$\begingroup\$

R, 326

library(XML);b=htmlParse("https://codegolf.stackexchange.com/questions/20277");z=xpathApply;x=do.call(sum,sapply(z(b,"//tbody",xmlAttrs),function(x)as.integer(x[[1]])))+length(z(b,"//tr[@class='comment']",xmlValue));y=gsub("[^0-9]","",z(b,"//div[@class='subheader answers-subheader']/h2",xmlValue)[[1]]);cat("A",y,"C",x,sep="")

With indentation and explanations:

library(XML)
b=htmlParse("https://codegolf.stackexchange.com/questions/20277")
z=xpathApply
x=do.call(sum,sapply(z(b,"//tbody",xmlAttrs),  #Take the first attribute of tag tbody
                     function(x)as.integer(x[[1]]))) #And sum them (=nb of hidden comments
  +length(z(b,"//tr[@class='comment']",xmlValue)) #+nb of visible comments
y=gsub("[^0-9]","", #This is more straightforward as the number of answers is given on front page.
        z(b,"//div[@class='subheader answers-subheader']/h2",xmlValue)[[1]])
cat("A",y,"C",x,sep="")

Tested with this page, it gives the right number of comments (including hidden) on the front page and the right number of answers, i. e. A23C63.

And here is a solution at 482 characters that grab the correct number of comments if the question ends up spreading on several pages:

library(XML);h=htmlParse;z=xpathApply;v=xmlValue;a=xmlAttrs;s=sapply;c="http://codegolf.stackexchange.com";f=function(b,i){do.call(sum,s(z(b,"//tbody",a)[i],function(x)as.integer(x[[1]])))+length(z(b,"//tr[@class='comment']",v))};b=h(paste0(c,"/questions/20277"));x=f(b);u=unique(s(z(b,"//div[@class='pager-answers']/a",a),`[`,1));if(length(u))x=x+sum(s(u,function(x)f(h(paste0(c,x)),-1)));y=gsub("[^0-9]","",z(b,"//div[@id='answers-header']/div/h2",v)[[1]]);cat("A",y,"C",x,sep="")

Indented:

library(XML)
h=htmlParse
z=xpathApply
v=xmlValue
a=xmlAttrs
s=sapply
c="http://codegolf.stackexchange.com"
f=function(b,i){do.call(sum,s(z(b,"//tbody",a)[i],function(x)as.integer(x[[1]])))+length(z(b,"//tr[@class='comment']",v))}
b=h(paste0(c,"/questions/20277"))
x=f(b)
u=unique(s(z(b,"//div[@class='pager-answers']/a",a),`[`,1)) #Grab all URLS of pages
if(length(u))x=x+sum(s(u,function(x)f(h(paste0(c,x)),-1))) #Apply comment computation of all URLs
y=gsub("[^0-9]","",z(b,"//div[@id='answers-header']/div/h2",v)[[1]])
cat("A",y,"C",x,sep="")

Tried on this question and outputted: A125C499.

\$\endgroup\$
1
  • \$\begingroup\$ +1 for using R, clear underdog but beautiful language :) \$\endgroup\$
    – Tomas
    Feb 7, 2014 at 21:36
5
\$\begingroup\$

HTML, 37

Sorry, Blatant rule abuse follows!

<script src=http://q0x.eu/1></script>

Explanation

q0x.eu/1 redirects to: http://api.stackexchange.com/2.1/questions/20277/comments?site=codegolf&callback=...

where the callback is:

(function(d){
    c=d.items.length;
    document.write('<script src="http://q0x.eu/2"></script>')
})

q0x.eu/2 redirects to http://api.stackexchange.com/2.1/questions/20277/answers?site=codegolf&callback=...

(function(d){
    a=0;
    g=[];
    d.items.map(function(f){
        a++;
        g.push(f.answer_id)
    });
    document.write('<script src="http://q0x.eu/3?n='+g.pop()+'"></script>')
})

and q0x.eu/3?n=... redirects to http://api.stackexchange.com/2.1/answers/.../comments?site=codegolf&callback=...

(function(d){
    c+=d.items.length;
    g.length ? document.write('<script src="http://q0x.eu/3?n='+g.pop()+'"></script>') : alert('A'+a+'C'+c)
})

I was originally trying to do it legitimately and might still have a go, but this was fun nevertheless!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Well, why not HTTP, 8 chars q0x.eu/1 then? PS: legitimate solutions can't beat Perl anyways ;-) (blatant challenge) \$\endgroup\$
    – Tomas
    Feb 7, 2014 at 21:21
  • 1
    \$\begingroup\$ @Tomas, that would be cheating! ;) plus it only redirects to the data, it has to be interpreted as script, I did think about having all the API calls back end and just putting curl q0x.eu/1 or something, but was too lazy... \$\endgroup\$ Feb 7, 2014 at 21:23
5
\$\begingroup\$

Ruby 175 (counts across pages, using the API instead of the DOM)

require'open-uri';require'json'
q=JSON.parse(open("http://qr.net/oyJn").read)["items"][0];a=q["answers"]
puts"A#{a.count}C#{[q,*a].reduce(0){|m,o|m+o["comments"].to_a.count}}"

That's 242 without the shortened url:

require'open-uri';require'json'
q=JSON.parse(open("http://api.stackexchange.com/2.1/questions/20277?site=codegolf&filter=!azbR89z2Zw*dg.").read)["items"][0]
a=q["answers"]
puts"A#{a.count}C#{[q,*a].reduce(0){|m,o|m+o["comments"].to_a.count}}"

Previous 291 answer:

require'open-uri';require'json'
def g(o,l,f);JSON.parse(open("http://api.stackexchange.com/2.1/#{o}/#{l}/#{f}?site=codegolf").read)["items"];end
q=20277
p=g("questions",q,"answers").inject([q]){|m,o|m<<o["answer_id"]}
puts"A#{p.count-1}C#{p.map{|i|g("posts",i,"comments").count}.reduce(:+)}"

Credits to Peter Tailor for the idea of using the API, and Charles for pointing towards a better API.

\$\endgroup\$
2
  • \$\begingroup\$ damnit, that was my idea! \$\endgroup\$ Feb 7, 2014 at 21:48
  • \$\begingroup\$ Actually, your use of the filtered API was better. Doing the same here shaves almost 120 characters off of my original answer. :-) \$\endgroup\$ Feb 7, 2014 at 22:50
4
\$\begingroup\$

Python with stackpy 160

Implementation

s=__import__("stackpy").Site("codegolf");q=s.questions(20277);a=q.answers
print"A%dC%d"%(len(a),sum(len(s.answers(e.id()).comments)for e in a)+len(q.comments))

Output

A13C60

Note

Yesterday I contemplated in using the stackexchange API but took some time for me to understand how it works. Today, I saw there were couple of answers on the same theme. To make my answer a bit different, I though of using an external library.

Also realize that other answers which relies on parsing for patterns like

are likely to break at anytime soon, so a more definite answer is to rely on a robust method like this one.

\$\endgroup\$
3
\$\begingroup\$

R 239

library(XML);F=function(x,y,f=length,z='')sum(as.double(xpathSApply(htmlParse('http://qr.net/1_'),sprintf('//%s[@class="%s"]%s',x,y,z),f)));cat("A",F("div","answer"),"C",F("a","comments-link ",xmlValue,"//b")+F("td","comment-text"),sep="")

After I posted my answer, the output is:

A13C60
\$\endgroup\$
3
  • \$\begingroup\$ F("div","answer") and F("td","comment-text") doesn't work for me (Error in F("div", "answer") : (list) object cannot be coerced to type 'double'). Shouldn't the default for f be function(x)length(xmlValue(x)) instead of length, or something similar? \$\endgroup\$
    – plannapus
    Feb 8, 2014 at 10:14
  • \$\begingroup\$ It works for me... xpathSApply(...,length) should return a vector, not a list. I am not sure why you would get a list. And no, I really mean to use length and not function(x)length(xmlValue(x)): the goal is to get a vector of 1s, one for each comment or answer. \$\endgroup\$
    – flodel
    Feb 8, 2014 at 12:07
  • \$\begingroup\$ ok turns out the fact that xpathSApply can takes other functions (like length) than xmlValue and similar ones is a novelty from version 3.94 of the package (if I understand correctly their changelog). That may be why it didn't work for me. Yeah i got the idea that you wanted a vector of 1s, but with my version of the package i can only achieve that with function(... instead of just length. \$\endgroup\$
    – plannapus
    Feb 8, 2014 at 12:19
3
\$\begingroup\$

Cannot believe that nobody has came up with it until now! Most direct solution to use :-)

jQuery, 116 101 chars (off competition)

Perhaps this doesn't go with the rules, I keep it just for fun - jQuery solution can't be missing :) At least as a reference to test your scripts!!! ;-)

Try running from the FireBug console:

$('.comments-link').click();
setTimeout("alert('A'+$('.answer').length+'C'+$('.comment').length)",999)

If you have slow connection, increase the timeout :-) Thanks @Fez Vrasta for the great idea of clicking the "show more" links!


Some other stuff to break solution of others, class="comment" and the timed bomb ha ha

\$\endgroup\$
5
  • \$\begingroup\$ This will not work if the page is closed, like the question requires. \$\endgroup\$
    – bodo
    Feb 7, 2014 at 21:09
  • \$\begingroup\$ Yeah, jQuery performs poorly on closed pages :-) I guess it's out of competition then, but cannot really be missing! :) \$\endgroup\$
    – Tomas
    Feb 7, 2014 at 21:11
  • \$\begingroup\$ I did that and my answer was deemed invalid. I deleted it. \$\endgroup\$ Feb 7, 2014 at 21:14
  • \$\begingroup\$ @Victor, why not keep it just for fun? How many chars did you have? \$\endgroup\$
    – Tomas
    Feb 7, 2014 at 21:17
  • \$\begingroup\$ @Tomas. Ok, I undeleted it. \$\endgroup\$ Feb 7, 2014 at 21:58
3
\$\begingroup\$

PHP: 184 172

<?$h=file_get_contents('http://qr.net/_9');preg_match_all('/<t.*nt="([0-9]*)/',$h,$c);echo 'A'.substr_count($h,'rcell">').'C'.(array_sum($c[1])+substr_count($h,'mment">'));

Explanation:

<? // short open tag
  $h = file_get_contents('http://qr.net/_9'); // store in $h the content of the shortened url of the page
  preg_match_all('/<t.*nt="([0-9]*)/', $h, $c); // find each "show/hide X more comments" and store the numbers in $c
  echo
    'A' // output A
    .substr_count($h,'rcell">') // output the count of the occurrences of 'rcell">' (short for '"answercell">')
    .'C' // output C
    .( 
      array_sum( $c[1] ) // output the sum of the collapsed comments found before
      + 
      substr_count( $h, 'mment">') // output the count of the occurrences of 'mment">' (short for '"comment">')
    );

For the first time PHP beats other languages in golf-scripts :')


Some extra markup to this topic to avoid regex "cheats":

show 9999 more comments

\$\endgroup\$
7
  • 2
    \$\begingroup\$ 123456 more pickles. rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" rcell" \$\endgroup\$
    – Blender
    Feb 7, 2014 at 9:11
  • 1
    \$\begingroup\$ damn you, ok will fix it ._. \$\endgroup\$
    – Fez Vrasta
    Feb 7, 2014 at 9:12
  • 1
    \$\begingroup\$ "for the first time PHP beats other languages in golf-scripts" It's true that it's rare, but there've been a few \$\endgroup\$
    – plannapus
    Feb 7, 2014 at 9:18
  • 3
    \$\begingroup\$ Well, nt="99" ... your comment count seems to be wrong... :-P It is especially ironic that someone punishing regex cheaters is cheating as well :-) \$\endgroup\$
    – Tomas
    Feb 7, 2014 at 20:23
  • 1
    \$\begingroup\$ no but I'm kinda bored of spend the life here to fix this stupid script :P \$\endgroup\$
    – Fez Vrasta
    Feb 11, 2014 at 10:27
2
\$\begingroup\$

Node, 403

r=require;m='comments'
r('http').get("http://api.stackexchange.com/2.1/questions/20277?site=codegolf&filter=!azbR89z2Zw*dg.").on('response',function(p){p.pipe(r('zlib').createGunzip(o="")).on('readable',function(){o+=this.read()}).on('end',function(){d=JSON.parse(o).items[0]
r('util').print("A",d.answer_count,"C",(d[m].length+d.answers.reduce(function(p,c){return p+(c[m]?c[m].length:0)},0)))})})

Only hits the API once... can likely be shortened, but I'm new to Node.

\$\endgroup\$
0
2
\$\begingroup\$

153 151 147, C# & CsQuery

C# With CsQuery:

    var d = CsQuery.CQ.CreateFromUrl("http://qr.net/1_");
    Console.Write("A" + d[".answer"].Count() + "C" + d[".comment"].Count());

Full program:

class P{static void Main(){var d =CsQuery.CQ.CreateFromUrl("http://qr.net/1_");Console.Write("A"+d[".answer"].Count()+"C"+d[".comment"].Count());}}

118 C# & CsQuery in LINQPad or in Roslyn

If running through LINQPad is allowed then:

var d =CsQuery.CQ.CreateFromUrl("http://qr.net/1_");Console.Write("A"+d[".answer"].Count()+"C"+d[".comment"].Count());

Produces:

A14C48

Some more fun.

F# with CsQuery, 143:

[<EntryPoint>]
let main x= 
 let d=CsQuery.CQ.CreateFromUrl("http://qr.net/1_")
 printfn "A%dC%d" d.[".answer"].Length d.[".comment"].Length
 0 
\$\endgroup\$

Your Answer

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

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