Which is better - Emacs or Vim? (Google fight)

26

1

Greetings, noble code golfers. Today you will resolve the most ancient and distinguished of debates - Emacs or Vim?

Your challenge is to take two search terms as input, and output which of those terms has the most Google search results. (This is obviously completely fair. What do you mean, biased?)

Here are some example inputs and outputs:

Input: emacs and vim
Output: vim (totally not creating any flamewars in the comments)

Input: google and microsoft
Output: google

Input: code golf stack exchange and code review stack exchange
Output: code golf stack exchange (yeah!)

And here are some edge cases just for fun (and for testing your solutions):

Input: About 1,000,000 results and About 100,000 results
Output: About 100,000 results

Input: This will autocotrect and Another testcase
Output: Another testcase (if you don't consider autocorrecting, then the first one will win)

For the following test cases, you must remove the # signs in the search terms first, since they rely on the term having a specific amount of results and posting the term here would ruin that.

Input: Thissear#chter#mhasno#results and Another testcase
Output: Another testcase (just a test for zero results)

Input: "These exact wo#rds do#n't exi#st# on the Internet" and Another testcase
Output: Another testcase (testing "s)

Input: Abo#ut 1,65#2,85#3,2#86 re#sults and Another testcase
Output: Another testcase (this one is tricky - the above search term has one result)

Input: "Abo#ut 4#8,234,8#75,14#7 res#ults" and Another testcase
Output: Another testcase (also tricky - no results, so it displays the search term)

You don't need to handle the corner-case of "quoted" searches returning "No results, showing results without quotes instead" because that would just be too complicated. You don't need to handle inputs with the same number of results either.

This is , so the shortest code in bytes will win!

Doorknob

Posted 2014-04-04T12:28:23.023

Reputation: 68 138

Psst... you should change the accepted answer :D – cat – 2016-03-29T21:11:38.577

@tac Alternatively, I can golf it down instead, which I did. ;) – Doorknob – 2016-03-29T23:12:07.543

How flexible's the output / return value? Does it have to be a string, or can it be an array containing the string and the number of results it had, or an array containing just the string? – cat – 2016-03-30T13:24:12.333

3it's so clear than vim is better I was surprised on this question that anyone could believe that something is better – Downgoat – 2016-04-03T00:14:29.673

Answers

5

Factor, 305 201 196 200 201 188 184 182 179 169 178 171 165 199 171 170 165 163 bytes

A language nearly as verbose as Java, beating Ruby... and Powershell! :D

Better regex, now. Thanks to @fede s. for 5 bytes off!

[ dup [ url-encode "google.com/search?nfpr=1&q="prepend http-get R/ s">About [\d,]+/ first-match " "split second 10 >base ] map zip [ last ] sort-with last first ]

Or 159 157 if the output can be like { "vim" 9782948234 }:

[ dup [ url-encode "google.com/search?nfpr=1&q="prepend http-get R/ s">About [\d,]+/ first-match " "split second 10 >base ] map zip [ last ] sort-with last ]

On the other hand, if we want to be unkillable, for 199 196 193 bytes:

[ dup [ url-encode "google.com/search?nfpr=1&q="prepend scrape-html nip dup "resultStats"find-by-id-between second text>> " "split second string>number ] map zip [ last ] sort-with last first ]

Unkillable because it parses HTML, so way more robust than the answers using regex.

cat

Posted 2014-04-04T12:28:23.023

Reputation: 4 989

1And python. Good for Factor. :P – Rɪᴋᴇʀ – 2016-03-29T21:13:13.260

@EasterlyIrk so close yet so far – cat – 2016-03-30T13:07:46.543

@EasterlyIrk I did it! – cat – 2016-03-30T13:20:57.473

This is missing the nfpr query string parameter, so it will fail for the autocorrect test cases. It also probably fails for a search term containing About 1 or similar. (I don't have Factor, so I can't test it.) – Doorknob – 2016-03-31T02:52:05.267

@Doorknob fixed – cat – 2016-04-01T16:00:33.217

@Doorknob In that case, wouldn't any other regex solution also fail? – cat – 2016-04-03T00:12:35.333

1Someone should make a Factor golfing dialect, so much whitespace, words so long... Well done, man! – fede s. – 2016-04-03T01:57:29.337

@fedes. I've been thinking about it, in fact, I'm just not sure how to actually do it since there are so. many. words and so. many. vocabularies just in the standard lib. If you've got ideas, I'm all ears :D – cat – 2016-04-03T01:59:43.050

1Thank you for the unkillable method. It's actually shorter in powershell than using a regex. (Yet still 2 bytes longer than your regex answer). I wouldn't call powershell succint though, it's command names are rarely short (iwr happens to be a default alias for invoke-webrequest and sort for sort-object, otherwise it'd be that much longer) – Jonathan Leech-Pepin – 2016-04-06T20:06:51.343

7

Of the text editors mentioned in the problem, only one of them can solve this on its own...

Emacs: 137 keystrokes

<C-o><C-u><C-k>(if(<<C-y><C-y><M-<><C-n><F3><C-a>http://google.com/search?nfpr=1&q=<C-S-e><M-x>r-st<RET> <RET>+<RET><C-a><C-k><M-x>b-em<RET><C-y><RET><C-x><C-q><C-s><RET>ts"><RET><M-z><<C-x>0<C-y>0 r<C-a><C-M-s><RET>[0-9]<RET><C-b><M-z> <C-a><C-y><C-k><C-S-a><M-x><up><up><RET>,<RET><RET><F4><C-n><F4><C-e>)(next-line)())<C-x><C-e><C-n><C-a><C-k><C-x>h<DEL><C-y>

It expects the first search terms to be on the first line and the second search terms to be on the second line, with the cursor at the beginning of the buffer.

For those unfamiliar with Emacs,

  • C-s means Ctrl-S.
  • M-z means Alt-Z (Alt is likely your meta key)
  • M-< means Alt-< or Alt-Shift-,
  • C-S-e means Ctrl-Shift-e

For those familiar with Emacs,

  • Start emacs with emacs -q. That doesn't load your .emacs file, so any fancy packages won't intefere with this.

Explanation

  1. Write the beginning of the elisp statment shell

    • <C-o><C-u><C-k> Saves the arguments with a newline
    • (if(<<C-y><C-y> Write the start of the if statement and places 2 copies of the arguments
    • <M-<><C-n> Move to the second line
  2. Define the HTTP macro. This converts the argument to a Google search URL and then returns the number of search results.

    • <F3> Start defining the keyboard macro
    • <C-a> Move to the start of the search term.
    • http://google.com/search?nfpr=1&q= Prepend the search URL
    • <C-S-e><M-x>r-st<RET> <RET>+<RET> Replace all the spaces with + signs.
    • <C-a><C-k><M-x>b-em<RET><C-y><RET> Emacs retrieve the raw HTML (b-em is short for browse-url-emacs)
    • <C-x><C-q> Make the file writable (required so the macro doesn't error ou t)
    • <C-s><RET>ts"><RET> Move to the number of results div (need to do a regular search because emacs macros rely on isearch to work)
    • <M-z><Cut the text of of the diff (this is why the was required)
    • <C-x>0 Switch back to the original buffer
    • <C-y>0 r;; Put the results back on the line ('0 r' handles no results)
    • <C-a><C-M-s><RET>[0-9]<RET><C-b><M-z> <C-a><C-y><C-k>;; Extract the number from the string.
    • <C-S-a><M-x><up><up><RET>,<RET><RET> Strips commas out of the number
    • <F4> Finish the keyboard macro
  3. Move down and execute the keyboard macro on the next line.

    • <C-n> Goes to the next line
    • <F4> Repeat the macro once.
  4. Finish up the elisp statement and execute it

    • <C-e>)(next-line)()) Finish up the elisp statement
    • <C-x><C-e> Evaluate the elisp command
    • <C-n><C-a><C-k> Kill the winning argument
    • <C-x>h<DEL> Delete everything else
    • <C-y> Paste the winning argument

Running It Yourself

Luckily you don't have to type all those keystrokes in perfectly! The meat and potatoes is all in a macro that you can just copy and paste. The macro can be copy and pasted into emacs!

1.Edit the keyboard macro <C-x><C-k><C-e>
2.Paste this into the whole buffer (paste should be <C-y>)

;; Keyboard Macro Editor.  Press C-c C-c to finish; press C-x k RET to cancel.
;; Original keys: C-a http://google.com/search?nfpr= 1&q= S-C-e M-x r-st RET SPC RET + RET C-a C-k M-x b-em RET C-y RET C-x C-q C-s RET ts"> RET M-z < C-x 0 C-y 0 SPC r C-a M-C-s [0-9] 5*DEL RET [0-9] RET C-b M-z SPC C-a C-y C-k S-C-a M-x 2*<up> RET , 2*RET
Command: last-kbd-macro
Key: none
Macro:
C-a         ;; move-beginning-of-line
http://google.com/search?nfpr=  ;; self-insert-command * 30
1&q=            ;; self-insert-command * 4
S-C-e
M-x         ;; execute-extended-command
r-st            ;; self-insert-command * 4
RET         ;; newline
SPC         ;; self-insert-command
RET         ;; newline
+           ;; self-insert-command
RET         ;; newline
C-a         ;; move-beginning-of-line
C-k         ;; kill-line
M-x         ;; execute-extended-command
b-em            ;; self-insert-command * 4
RET         ;; newline
C-y         ;; yank
RET         ;; newline
C-x C-q         ;; read-only-mode
C-s         ;; isearch-forward
RET         ;; newline
ts">            ;; self-insert-command * 4
RET         ;; newline
M-z         ;; zap-to-char
<           ;; self-insert-command
C-x 0           ;; delete-window
C-y         ;; yank
0           ;; self-insert-command
SPC         ;; self-insert-command
r           ;; self-insert-command
C-a         ;; move-beginning-of-line
M-C-s           ;; isearch-forward-regexp
RET         ;; newline
[0-9]           ;; self-insert-command * 5
RET         ;; newline
C-b         ;; backward-char
M-z         ;; zap-to-char
SPC         ;; self-insert-command
C-a         ;; move-beginning-of-line
C-y         ;; yank
C-k         ;; kill-line
S-C-a
M-x         ;; execute-extended-command
2*<up>          ;; previous-line
RET         ;; newline
,           ;; self-insert-command
2*RET           ;; newline
  1. Type <C-c><C-c> to save the macro.
  2. If following the explanation steps, replace step 2 with <F4> to run the macro (or just run it on its own to try)

Caveats

  1. You can't run the macro on the same search twice without killing the buffer the HTML gets loaded into. Kill the buffers
    • <C-x><k> search<TAB>
    • Choose one of the buffers in this list to kill.
    • Repeat for all the buffers beginning with "search"
  2. If you run the macro too much, Google will think you are a robot and block access for atime
    • If the macro returns something like <input type="submit" name="submit" value="Submit"...>, then this likely occurred.
    • You can confirm it by looking at the raw HTML (<C-x><C-b> and choose the buffer with the search term in it).
    • If you see stuff about robots and captcha, Google's blocking you. It's not my fault.

Dominic A.

Posted 2014-04-04T12:28:23.023

Reputation: 533

This is really cool! Of the text editors mentioned in the problem, only one of them can solve this on its own... is that even true? are there really no HTTP libraries for vimscript? – cat – 2017-06-21T22:36:22.320

There's at least nothing in vanilla vim, but brief googling didn't pop up any vimscript HTTP libraries. I can't imagine why anyone would actually write that when you could just read the results of curl and get the same effect. (but then your answer should indicate that it's vim+curl). – Dominic A. – 2017-06-24T11:40:33.150

7

Ruby, 203 180 bytes

->*s{s.map{|x|[(open("http://www.google.com/search?nord=1&q=#{URI.escape x}&nfpr=1").read.match(/s">(About )?([\d,]+) result/)||[?0])[-1].split(?,).join.to_i,x]}.max[1]}

+11 bytes for the -ropen-uri flag (plus space).

Input is taken as two arguments.

URL explanation:

  • ?nord=1: prevent auto-redirect from HTTP to HTTPS
  • &q=#{URI.escape x}: escape the query so "s work
  • &nfpr=1: no autocorrect

The whole map turns ['emacs','vim'] into [[2150000, 'emacs'], [14900000, 'vim']]. (You can see this by changing the .max[1] at the end to .inspect.) Then, the max is taken, which will grab the one with the most results, and [1] is used to get the search term.

Doorknob

Posted 2014-04-04T12:28:23.023

Reputation: 68 138

You can save a few more bytes by requiring in the command ruby -ropen-uri instead of in the file. – Shelvacu – 2016-03-26T00:01:10.463

Why won't this (and the other regex answers) break on searches like "About 100,000,000 results"? – cat – 2016-04-02T23:26:20.067

@cat Note the s"> at the start of the regex. That makes sure the result count is preceded by a certain HTML tag (I don't remember which one; probably something like <span id="num-results"> or something). – Doorknob – 2016-04-03T14:51:08.513

@Doorknob Ooh, I didn't see that at first (by the way, it's <div id="resultStats"> :P)

– cat – 2016-04-03T15:19:48.680

Searching for Thissear#chter#mhasno#results will now show this question on Google :) Interestingly it's showing 2 results (for me at least!) - http://www.google.com/search?nord=1&nfpr=1&q=Thissear%23chter%23mhasno%23results NB. Any regex matching "About * results" will miss the found result on this page :(

– draegtun – 2014-04-06T17:29:59.577

It doesn't work for me. http://ideone.com/UqEyBn

– TheDoctor – 2014-04-08T17:05:16.217

@TheDoc It doesn't work on Ideone - run it on actual Ruby – Doorknob – 2014-04-08T17:09:21.497

3

Java, 828 800 783 744 739 687 bytes

import java.net.*;import java.util.*;import java.util.regex.*;interface G{static Scanner s(String a)throws Exception{URL u=new URL("http://google.com/search?q="+a);HttpURLConnection c=(HttpURLConnection)u.openConnection();c.addRequestProperty("User-Agent","Mozilla/4.0");return new Scanner(c.getInputStream());}static void main(String[]r)throws Exception{String a,b;String c=s(a=r[0]).useDelimiter("\\Z").next(),d=s(b=r[1]).useDelimiter("\\Z").next();Matcher m=Pattern.compile("ut ([0-9,]+) res").matcher(c);m.find();long i=new Scanner(m.group(1)).nextLong();m=Pattern.compile("ut ([0-9,]+) res").matcher(d);m.find();long j=new Scanner(m.group(1)).nextLong();System.out.print(i>j?a:b);}}

SuperJedi224

Posted 2014-04-04T12:28:23.023

Reputation: 11 342

Holy cats. The imports alone are 79 bytes... perhaps you should try Groovy? :P – cat – 2016-03-30T02:01:31.750

1I'm really entertained by the fact you have to set the user-agent string yourself. Like, as if Java wasn't verbose enough – cat – 2016-03-30T02:02:50.377

Because google gives a 403 if you don't. – SuperJedi224 – 2016-03-30T02:03:19.403

2Why not take input from args instead of StdIn? – Pavel – 2017-02-08T21:09:28.717

2

Python 3, 227 226 208 213 226 220 221 206 202 200 198 bytes

import re,requests as r,urllib.parse as u
lambda*t:sorted(zip(map(lambda a:int(re.findall("s\">About ([\d,]+)",r.get("http://google.com/search?q="+u.quote(a)).text)[0].replace(",","")),t),t))[-1][1]

Assign the lambda to something to call it.

Uses the requests library.

Ungolfed:

import re, requests as r, urllib.parse as u
lambda*t:
  sorted(
  list(
      zip(map(
              lambda a: int(re.findall("About ([\d,]+)",
               r.get("http://google.com/search?q="+u.quote(a)).text)[0].replace(",","")),
              t
          ),
       t)
   )
)[-1][1]

cat

Posted 2014-04-04T12:28:23.023

Reputation: 4 989

This doesn't work on my machine even after installing requests: NameError: name 'quote' is not defined – Shelvacu – 2016-03-26T00:19:06.140

@shelvacu Oops, I'm smart, I forgot to change quote back to urllib.parse.quote after an absolute import. – cat – 2016-03-26T00:20:33.533

did you test this? It also looks like google.co/search gives 404 whereas google.com/search works – Shelvacu – 2016-03-26T00:26:09.317

@shelvacu yes, I tested it, it gives the same results as the ruby answer and the question says. – cat – 2016-03-26T00:26:59.400

1

Powershell, 175, 172 bytes

($args|%{[pscustomobject]@{'a'=$_;'b'=[int]((iwr "google.com/search?nord=1&q=$_&nfpr=1").parsedhtml.getelementbyid('resultstats').innertext-split" ")[1]}}|sort -des b).a[0]

Showing the score as well as the name would cut 2 more bytes.

This uses the same unkillable feature as the 196 Byte Factor answer (Parsed HTML) and cuts down from the previous regex answer.

Jonathan Leech-Pepin

Posted 2014-04-04T12:28:23.023

Reputation: 273

1

Racket, 360 337 bytes

#lang racket(require net/url net/uri-codec)(λ(t)(cddr(sort(map list t(map(lambda(a)(string->number(string-replace(list-ref(string-split(car(regexp-match#px"s\">About [\\d,]+ res"(call/input-url(string->url(string-append"http://google.com/search?nfpr=1&q="(uri-encode a)))(curry get-pure-port)port->string)))" ")1)",""")))))#:key cdr <)))

0.o

There's a reason they call it Lost In a Sea of Parentheses.

Ungolfed:

#lang racket
(require net/url)
(require net/uri-codec)

(define (open-url term)
  (call/input-url
   (string->url (string-append "http://" term))
   (curry get-pure-port #:redirections 5)
   port->string))

(define (get-result term)
  (string->number
   (string-replace
    (list-ref
     (string-split
      (car (regexp-match #px"s\">About [\\d,]+ results" (open-url (string-append "google.com/search?nfpr=1&q=" (uri-encode term)))))
      " ")
     1)
    "," "")))

(define (zip a b) (map list a b))

(define (google-fite terms) (cddr (sort (zip terms (map get-result terms))) #:key cdr <))

cat

Posted 2014-04-04T12:28:23.023

Reputation: 4 989