Created
December 30, 2015 05:36
-
-
Save kwcto/c36a7ae9f5f6392eb167 to your computer and use it in GitHub Desktop.
Score full-sentence answers from Typeform for similarity against a provided answer key with OpenOffice (Javascript macro)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See https://gist.github.com/kwcto/3cd3009b8cc12525669b to grade a simpler single-column set of answer rows | |
// | |
// Instructions for running Macros: | |
// https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Using_the_Scripting_Framework | |
// | |
// Check OpenOffice speadsheet text cells for similarity to a provided set of answers | |
// Will Sahatdjian - 12-29-2015 | |
// | |
// Based on original work by: | |
// Copyleft 2010 by Kas Thomas | |
// http://asserttrue.blogspot.com/ | |
// !!! CHANGE THESE PARAMETERS !!!! | |
// zero-based positions | |
var ANSWER_FIRST_ROW_NUMBER = 5; // skip first 5 rows because they aren't answers | |
var ANSWER_FIRST_COLUMN_NUMBER = 2; // skip first 2 columns because those aren't answers | |
var ANSWER_KEY = [] { | |
"Perfect sentence number one", | |
"Perfect sentence number two", | |
"Perfect sentence number three", | |
"Perfect sentence number four", | |
"I plead tha fizzif" | |
}; | |
// !!! NO CHANGES NECESSARY AFTER THIS POINT !!!! | |
importClass(Packages.com.sun.star.uno.UnoRuntime); | |
importClass(Packages.com.sun.star.sheet.XSpreadsheetDocument); | |
// go thru the sheet one row at a time | |
// and collect cell data for answer rows | |
// check Levenshtein distance to compute "error rate" | |
function harvestCells( sheet, rows, columns ) { | |
var masterArray = []; | |
for (var i = 0; i < rows; i++) { | |
var student_row = i - ANSWER_FIRST_ROW_NUMBER; | |
if(student_row < ANSWER_FIRST_ROW_NUMBER) { | |
continue; | |
} | |
var ar = []; | |
for (var k = 0; k < columns; k++) { | |
var answer_number = k - ANSWER_FIRST_COLUMN_NUMBER; | |
if(answer_number < 0 || answer_number >= ANSWER_KEY.length) { | |
continue; | |
} | |
var cell = sheet.getObject().getCellByPosition( k,i ); | |
var content = cell.getFormula(); | |
var answer = ANSWER_KEY[answer_number]; | |
var errors = getEditDistance(answer, content); | |
var accuracy = Math.round(accuracy(answer, content) * 100); | |
ar.push("EXPECTED: \"" + answer + "\" | ACTUAL: \"" + content + "\" | ERRORS: " + errors + " | ACCURACY: " + accuracy); | |
} | |
masterArray.push(ar) | |
} | |
return masterArray; | |
} // harvestCells() | |
// Levenshtein | |
// https://gist.github.com/andrei-m/982927 | |
function getEditDistance(a, b){ | |
if(a.length == 0) return b.length; | |
if(b.length == 0) return a.length; | |
var matrix = []; | |
// increment along the first column of each row | |
var i; | |
for(i = 0; i <= b.length; i++){ | |
matrix[i] = [i]; | |
} | |
// increment each column in the first row | |
var j; | |
for(j = 0; j <= a.length; j++){ | |
matrix[0][j] = j; | |
} | |
// Fill in the rest of the matrix | |
for(i = 1; i <= b.length; i++){ | |
for(j = 1; j <= a.length; j++){ | |
if(b.charAt(i-1) == a.charAt(j-1)){ | |
matrix[i][j] = matrix[i-1][j-1]; | |
} else { | |
matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution | |
Math.min(matrix[i][j-1] + 1, // insertion | |
matrix[i-1][j] + 1)); // deletion | |
} | |
} | |
} | |
return matrix[b.length][a.length]; | |
}; | |
// Jaro-Winkler | |
// https://github.com/zdyn/jaro-winkler-js | |
function accuracy(string1, string2) { | |
var ch, i, j, jaro, k, l, len, len1, len2, m, matchWindow, n, numMatches, prefix, ref, ref1, ref2, string1Matches, string2Matches, transpositions, windowEnd, windowStart; | |
if (string1.length > string2.length) { | |
ref = [string2, string1], string1 = ref[0], string2 = ref[1]; | |
} | |
matchWindow = ~~Math.max(0, string2.length / 2 - 1); | |
string1Matches = []; | |
string2Matches = []; | |
for (i = k = 0, len = string1.length; k < len; i = ++k) { | |
ch = string1[i]; | |
windowStart = Math.max(0, i - matchWindow); | |
windowEnd = Math.min(i + matchWindow + 1, string2.length); | |
for (j = l = ref1 = windowStart, ref2 = windowEnd; ref1 <= ref2 ? l < ref2 : l > ref2; j = ref1 <= ref2 ? ++l : --l) { | |
if ((string2Matches[j] == null) && ch === string2[j]) { | |
string1Matches[i] = ch; | |
string2Matches[j] = string2[j]; | |
break; | |
} | |
} | |
} | |
string1Matches = string1Matches.join(""); | |
string2Matches = string2Matches.join(""); | |
numMatches = string1Matches.length; | |
if (!numMatches) { | |
return 0; | |
} | |
transpositions = 0; | |
for (i = m = 0, len1 = string1Matches.length; m < len1; i = ++m) { | |
ch = string1Matches[i]; | |
if (ch !== string2Matches[i]) { | |
transpositions++; | |
} | |
} | |
prefix = 0; | |
for (i = n = 0, len2 = string1.length; n < len2; i = ++n) { | |
ch = string1[i]; | |
if (ch === string2[i]) { | |
prefix++; | |
} else { | |
break; | |
} | |
} | |
jaro = ((numMatches / string1.length) + (numMatches / string2.length) + (numMatches - ~~(transpositions / 2)) / numMatches) / 3.0; | |
return jaro + Math.min(prefix, 4) * 0.1 * (1 - jaro); | |
}; | |
// a Swing UI for displaying the data | |
function EditorPane( ) { | |
Swing = Packages.javax.swing; | |
this.pane = new Swing.JEditorPane("text/html","" ); | |
this.jframe = new Swing.JFrame( ); | |
this.jframe.setBounds( 100,100,500,400 ); | |
var editorScrollPane = new Swing.JScrollPane(this.pane); | |
editorScrollPane.setVerticalScrollBarPolicy( | |
Swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); | |
editorScrollPane.setPreferredSize(new java.awt.Dimension(150, 150)); | |
editorScrollPane.setMinimumSize(new java.awt.Dimension(10, 10)); | |
this.jframe.setVisible( true ); | |
this.jframe.getContentPane().add( editorScrollPane ); | |
// public methods | |
this.getPane = function( ) { return this.pane; } | |
this.getJFrame = function( ) { return this.jframe; } | |
} | |
( function main( ) { | |
//get the document object from the scripting context | |
oDoc = XSCRIPTCONTEXT.getDocument(); | |
//get the XSpreadsheetDocument interface from the document | |
xSDoc = UnoRuntime.queryInterface(XSpreadsheetDocument, oDoc); | |
// get a reference to the sheets for this doc | |
var sheets = xSDoc.getSheets(); | |
// get Sheet1 | |
var sheet1 = sheets.getByName("Sheet1"); | |
// construct a new EditorPane | |
var editor = new EditorPane( ); | |
var pane = editor.getPane( ); | |
// harvest cell data (from sheet, rows, cols) | |
var masterArray = harvestCells( sheet1, 100,8 ); | |
// display the data | |
var text = masterArray.join("\n") ; | |
pane.setText( text ); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment