I came across SVGCaptcha, and immediately knew it was a bad idea.

I would like you to show just how bad an idea this is by extracting the validation code from the SVG images that code produces.

An example image looks like this:
Here is the source of the example image:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
             width="200" height="40"
    > <rect x="0" y="0" width="200" height="40" 
        style="stroke: none; fill: none;" >
        </rect> <text style="fill: #4d9363;" x="5" y="34" font-size="20" transform="translate(5, 34) rotate(-17) translate(-5, -34)">8</text>
<text style="fill: #be8b33;" x="125" y="29" font-size="21" transform="translate(125, 29) rotate(17) translate(-125, -29)">f</text>
<text style="fill: #d561ff;" x="45" y="35" font-size="20" transform="translate(45, 35) rotate(-2) translate(-45, -35)">4</text>
<text style="fill: #3de754;" x="85" y="31" font-size="21" transform="translate(85, 31) rotate(-9) translate(-85, -31)">8</text>
<text style="fill: #5ed4bf;" x="25" y="33" font-size="22" transform="translate(25, 33) rotate(16) translate(-25, -33)">u</text>
<text style="fill: #894aee;" x="105" y="28" font-size="25" transform="translate(105, 28) rotate(9) translate(-105, -28)">1</text>
<text style="fill: #e4c437;" x="65" y="32" font-size="20" transform="translate(65, 32) rotate(17) translate(-65, -32)">x</text>

The input is the SVG image, which is a textual format.

The only real restriction is that your code must produce the values in the correct order.
The input <text> elements are in random order so you have to pay attention to the x attribute in the <text> tag

Score is the number of bytes in the code

Since the code currently does two transforms that cancel each-other out you can ignore them, but if you do take them in consideration, go ahead and take a 30% reduction from your score.

  • 3
    \$\begingroup\$ You haven't actually stated explicitly what the input and output are: I'm presuming the SVG file and the letters contained therein? And it's not clear to me whether answers are required to actually implement the SVG spec or whether they can assume that the SVG is generated by the current version of SVGCaptcha and so the transforms can be ignored. \$\endgroup\$ Commented Nov 15, 2015 at 22:51
  • \$\begingroup\$ I suggest limiting the output to STDOUT or function return value, and making it code-golf \$\endgroup\$
    – TheDoctor
    Commented Nov 15, 2015 at 22:54
  • 1
    \$\begingroup\$ No, questions need an objective, quantifiable winning criterion to be on-topic for this site. \$\endgroup\$
    – Alex A.
    Commented Nov 15, 2015 at 23:00
  • 7
    \$\begingroup\$ I'm not sure how relevant image-processing is here. \$\endgroup\$ Commented Nov 16, 2015 at 0:42
  • 19
    \$\begingroup\$ This question is now the 4th result when googling 'svgcaptcha' :) \$\endgroup\$
    – Blue
    Commented Nov 16, 2015 at 9:33

16 Answers 16


Bash, 63 56 39 bytes

cat<<_|grep -o 'x=.*>'|cut -c4-|sort -n|grep -o '>.</t'|cut -c2

grep -o 'x=.*>'|cut -c4-|sort -n|grep -o '>.</t'|cut -c2

grep -o 'x=.*<'|sort -k1.4n|rev|cut -c2

Note: requires cat, grep, sort, rev, and cut. Takes input from stdin. The output is separated by line breaks on stdout. Make sure to press CTRL+D (not COMMAND+D on Mac) when finished entering the CAPTCHA. Input must be followed by a newline and then '_'.

EDIT: Saved 13 bytes.

EDIT 2: Saved 20 bytes thanks to @manatwork!

  • \$\begingroup\$ GNU coreutils sort supports character position in the keydef: cut -c4-|sort -nsort -k1.4n. \$\endgroup\$
    – manatwork
    Commented Jan 18, 2018 at 10:56
  • \$\begingroup\$ @manatwork Thanks, I updated the answer. \$\endgroup\$
    – Coder-256
    Commented Jan 18, 2018 at 21:55

CJam, 26 bytes


Try it online in the CJam interpreter.

How it works

q     e# Read all input from STDIN.
"x="/ e# Split it at occurrences of "x=".
2>    e# Discard the first two chunks (head and container).
{     e# Sort the remaining chunks by the following key:
  '"/ e#   Split at occurrences of '"'.
  1=  e#   Select the second chunk (digits of x="<digits>").
  i   e#   Cast to integer.
}$    e#
{     e# For each of the sorted chunks:
  '>/ e#   Split at occurrences of '>'.
  1=  e#   Select the second chunk.
  c   e#   Cast to character.
}/    e#

JavaScript, 95 93 91 bytes


edit: -2 bytes changing documentRoot to lastChild; -2 bytes changing join('') to join``, thanks Vɪʜᴀɴ

Enter code in the browser console on a page containg the SVG in question, writes to console output.

  • \$\begingroup\$ document.rootElement is retuning undefined. I've tried Firefox and Safari \$\endgroup\$
    – Downgoat
    Commented Nov 16, 2015 at 2:31
  • \$\begingroup\$ This was only tested in Chrome, I'll look into what could be changed. \$\endgroup\$
    – Taylor G
    Commented Nov 16, 2015 at 2:32
  • \$\begingroup\$ It appears to work in Firefox, is SVG the only content of the file? \$\endgroup\$
    – Taylor G
    Commented Nov 16, 2015 at 2:39
  • \$\begingroup\$ Okay, tried it in Chrome, now it worked. +1. You can also save two bytes by changing the ('') to two backticks: `` \$\endgroup\$
    – Downgoat
    Commented Nov 16, 2015 at 2:41
  • \$\begingroup\$ This is 78: t=>(l=[],r=/x="(\d*).*?>(.)/g,eval("while(e=r.exec(t))l[e[1]]=e[2];l.join``")) (takes xml string as parameter, returns captcha text) \$\endgroup\$
    – DankMemes
    Commented Nov 16, 2015 at 7:25

Perl, 40 bytes

39 bytes code + 1 for -n

$a[$1]=$2 for/x="(.+)".+(.)</g}{print@a


perl -ne '$a[$1]=$2 for/x="(.+)".+(.)</g}{print@a' <<< '<example from above>'
  • \$\begingroup\$ Man that is just full of warnings if you turn them on. Excellent use of Perl's default lax nature. \$\endgroup\$ Commented Nov 16, 2015 at 15:44
  • \$\begingroup\$ @BradGilbertb2gills Yeah, I try not to test the warnings, I'm so surprised any golfed code even works sometimes! \$\endgroup\$ Commented Nov 17, 2015 at 8:49

Bash + GNU utilities, 53

grep -Po '(?<=x=").*(?=<)'|sort -n|grep -Po '(?<=>).'

Like this answer, output is one char per line.


Perl 6, 68 bytes

say [~] lines.map({/'x="'(\d+).*(.)\</??(+$0=>$1)!!()}).sort».value

Befunge, 79 bytes

It feels like it should be possible to golf at least one more byte off of this, but I've been working on it for a couple of days now, and this is as good as I could get it.


Try it online!


Source code with execution paths highlighted

* Make the execution direction right-to-left, and wrap around to start the main loop.
* Read a char from stdin, and test for the end-of-file value.
* If it's not end-of-file, check if it's a >.
* If it's not a >, add it to the value on the stack which tracks the last two characters, and check if the current pair matches x=.
* If not, multiply by 126 and mod with 1262 to drop the oldest value from the pair and make space for the next character.
* Wrap around again to repeat the main loop.
* When an x= pair is encountered, skip the next character (the quote), read an integer (the x value), and divide by 20. This becomes the current offset which is saved for later.
* When a > is encountered, read the next character (typically one of the captcha letters), and save that at the current offset in an "array". Reset the offset to 9, so the captcha letter won't be overwritten when later > characters are encountered.
* Finally, when then end-of-file is reached, iterate over the 7 values saved in the array and output them one by one. That should give you all the captcha letters in the correct order.

I'm glossing over some of the details here, since the code paths overlap each other in ways which are a little difficult to explain, but it should give you a general idea of how the algorithm works.


Python2, 129 bytes

import re,sys
print''.join(t[1] for t in sorted(re.findall(r'(\d+), -\d+\)"\>(.)\</t',sys.stdin.read()),key=lambda t:int(t[0])))

Takes the HTML source on stdin, produces code on stdout.

  • \$\begingroup\$ How does this sort the output? The <text> elements are in a random order, and the only real requirement is that you have to put them in the correct order. That means you have to use the x from the <text> and follow any transforms. \$\endgroup\$ Commented Nov 15, 2015 at 22:36
  • \$\begingroup\$ @BradGilbertb2gills I missed that the first time around, fixed now. \$\endgroup\$
    – orlp
    Commented Nov 15, 2015 at 22:43

Mathematica, 106 bytes


Note: The input needs to be in exactly the format specified by the example.


V, 28 26 25 24 bytes


Try it online!


d5j              delete first 6 lines
   Í<0x81>x=     In every line, replace everything up to x=" (inclusive) by nothing
ún               Sort numerically
J                Join line (closing </svg>) with next line
 Í<0x81>">       In every line, replace everything up to "> by nothing
l␖H$d            Visual block around closing </text> tags, delete
     Íî          In every line, replace \n by nothing.


00000000: 6435 6acd 8178 3d0a fa6e 0a4a cd81 223e  d5j..x=..n.J..">
00000010: 0a6c 1648 2464 cdee                      .l.H$d..

QuadS, 49 bytes

∊c[⍋⊃x c←↓⍎¨@1⍉(⊢⍴⍨2,⍨.5×≢)3↓⍵]

Try it online!

Finds x values (digit-runs after x=") and "letters" (pinned by closing and opening tags), then executes the following APL (where is the list of found x values and letters, in order of appearance):

3↓⍵ drop the first three elements (spaces around <rect/rect> and the <rect's x value).

() apply the following tacit function on that:

 the number of remaining items

.5× halve that

2,⍨ append a two

⊢⍴⍨ reshape to that shape (i.e. an n×2 matrix)

 transpose (to a 2×n matrix)

⍎¨@1 execute each string in the first row (turning them into numbers)

 split the matrix into two vectors (one per row)

x c← store those two in x (x values) and c (characters) respectively

 pick the first (x)

 grade up (the indices into x which would sort x)

c[] use that to index into c

ϵnlist (flatten) because each letter is a string by itself

The equivalent APL expression of the entire QuadS program is:

∊c[⍋⊃x c←↓⍎¨@1⍉(⊢⍴⍨2,⍨.5×≢)3↓'x="(\d+)"' '>(.)<'⎕S'\1'⊢⎕]

Java 8, 197 173 bytes

import java.util*;s->{String a[]=s.split("x=\""),r="";Map m=new TreeMap();for(int i=2;i<a.length;m.put(new Long(a[i].split("\"")[0]),a[i++].split(">|<")[1]));return m.values();}

Outputs a java.util.Collection of characters.


Try it online.

import java.util*;            // Required import for Map and TreeMap
s->{                          // Method with String as both parameter and return-type
  String a[]=s.split("x=\""), //  Split the input by `x="`, and store it as String-array
         r="";                //  Result-String, starting empty
  Map m=new TreeMap();        //  Create a sorted key-value map
  for(int i=2;                //  Skip the first two items in the array,
      i<a.length;             //  and loop over the rest
    m.put(new Long(a[i].split("\"")[0]),
                              //   Split by `"` and use the first item as number-key
                              //   Split by `>` AND `<`, and use the second item as value
    return m.values();}       //  Return the values of the sorted map as result

Gema, 65 characters


In Gema there is no sorting, but fortunately is not even needed.

Sample run:

bash-4.4$ gema 'x\="<D>*\>?=@set{$1;?};?=;\Z=${5}${25}${45}${65}${85}${105}${125}' < captcha.svg

XMLStarlet, 46 characters

xmlstarlet sel -t -m //_:text -s A:N:U @x -v .

Hopefully this is valid solution as XMLStarlet is transpiler that generates and executes XSLT code, which is a Turing complete language.

Sample run:

bash-4.4$ xmlstarlet sel -t -m //_:text -s A:N:U @x -v . < captcha.svg 

PHP, 96 bytes

Given that $i is the input string

preg_match_all('|x="(\d+).*(.)\<|',$i,$m);$a=array_combine($m[1],$m[2]);ksort($a);echo join($a);
  • 1
    \$\begingroup\$ Instead of array_combine() + ksort() you could use array_multisort() like this: array_multisort($m[1],$m[2]);echo join($m[2]);. But please note that solutions are expected to handle input and output themselves (unless the language does it automatically), instead of expecting to find the input in a variable or just leave the result in a variable. See related meta. \$\endgroup\$
    – manatwork
    Commented Jan 19, 2018 at 9:12

Clean, 277 150 bytes

Yay pattern matching!

import StdEnv,StdLib
?s=map snd(sort(zip(map(toInt o toString)[takeWhile isDigit h\\['" x="':h]<-tails s],[c\\[c:t]<-tails s|take 7 t==['</text>']])))

Try it online!

Defines the function ?, taking [Char] and giving [Char].


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.