Translates Morse code into readable text using conversion dictionary.
demorse (
string, *required*
dictionary *required*
)
function( | |
s, // string, Morse-encoded. | |
// Any char that is not "." or "-" is considered whitespace. | |
// One whitespace is the letter separator. 2+ whitespaces are the word separator. | |
t // string, substitution "table" between char and morse code | |
){ | |
// a single-replace code | |
return s.replace( | |
// Regexp: | |
// Capture any sequence of "." and "-" (greedy) and store into 1st paren. Then get any char if possible. (Due to "greedy" quantificator "any char" is never "." or "-") | |
// ELSE | |
// Capture any sequence of chars that are not "." or "-" (greedy). | |
// Dot inside square brackets may be unescaped. | |
/([.-]+).?|([^.-]+)/g, | |
function( | |
i, // full captured string. Its value is useless. | |
s, // "string". First captured paren that may contain only "." or "-". | |
f // "fail". Second captured string. Its certain value is useless, only string length. It's rather a flag. | |
){ | |
i=1; // Assign 1 to unused `i` variable. It will be offset constructed from .'s and -'s. | |
// If "fail" paren is captured it means that current char in original string is second whitespace, so this place is word boundary. Insert space here. | |
// If not, get char from "table"-string at certain offset: | |
return f ? ' ' : t.charAt ( | |
// Eval statement: | |
eval( | |
// Replace in "local" `s`... | |
s.replace( | |
/./g, // .. any char (it is only "." or "-") with... | |
// ... well.. with chunk of text. "$&" is the captured char. | |
"i=i*2-~$&1;" | |
// So if input is "-" the replacement is: | |
// i=i*2-~-1; | |
// And if it is ".": | |
// i=i*2-~.1; | |
// "~-1" is eval'd to 0; "~.1" is eval'd to -1. | |
) | |
// Thus, a sequence of these chunks each time doubles the `i` and adds or not 1. | |
// For example, if input string is "--...", `i` = (binary) 100111. | |
) | |
// And `i` is the return value of eval. | |
) || '?' // Finally, if there's no such char in table (invalid Morse code), use '?' instead. | |
} | |
) | |
} |
function(s,t){return s.replace(/([.-]+).?|([^.-]+)/g,function(i,s,f){i=1;return f?' ':t.charAt(eval(s.replace(/./g,"i=i*2-~$&1;")))||'?'})} |
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
Version 2, December 2004 | |
Copyright (C) 2011 subzey <[email protected]> | |
Everyone is permitted to copy and distribute verbatim or modified | |
copies of this license document, and changing it is allowed as long | |
as the name is changed. | |
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
0. You just DO WHAT THE FUCK YOU WANT TO. |
{ | |
"name": "deMorse", | |
"description": "Translates Morse code into readable text", | |
"keywords": [ | |
"morse" | |
] | |
} |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> | |
<title>demorse140 demo</title> | |
<style type="text/css"> | |
#message, | |
#raw { | |
border: solid gray 1px; | |
padding: 3px; | |
text-align: right; | |
white-space: nowrap; | |
overflow: hidden; | |
height: 1em; | |
} | |
h1 { | |
border: solid gray 1px; | |
background: lightgrey; | |
text-align: center; | |
font: normal normal normal 18px 'Tahoma', sans-serif; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Use space key</h1> | |
<pre id="message"></pre> | |
<pre id="raw"></pre> | |
<script type="text/javascript"> | |
var demorse = function(s,t){return s.replace(/([.-]+).?|([^.-]+)/g,function(i,s,f){i=1;return f?' ':t.charAt(eval(s.replace(/./g,"i=i*2-~$&1;")))||'?'})} | |
var morseTable = "??TEMNAIOGKDWRUS??QZYCXBJP?L?FVH09?8???7???????61???????2???3?45" | |
</script> | |
<script type="text/javascript"> | |
var keyState; | |
var morseMessage = ".---- ....- ----- -... -.-- - . ..."; | |
var lastDown = 0; | |
var lastUp = 0; | |
var ditLength = 200; | |
function keyStateChange(e){ | |
if (e.keyCode != 0x20) return; | |
if (!keyState && e.type=="keydown"){ | |
keyState = 1; | |
lastDown = +new Date; | |
var timeDiff = (lastDown - lastUp) / ditLength; | |
if (timeDiff >= 3){ | |
morseMessage += " "; | |
}; | |
if (timeDiff >= 7){ | |
morseMessage += " "; | |
}; | |
} else if (keyState && e.type=="keyup"){ | |
keyState = 0; | |
lastUp = +new Date; | |
if ((lastUp - lastDown) / ditLength >= 3){ | |
morseMessage += "-"; | |
} else { | |
morseMessage += "."; | |
}; | |
} else return; | |
updateView() | |
}; | |
if (document.addEventListener){ | |
document.addEventListener("keyup", keyStateChange, true); | |
document.addEventListener("keydown", keyStateChange, true); | |
} else if (document.attachEvent) { | |
document.attachEvent("onkeyup", keyStateChange, true); | |
document.attachEvent("onkeydown", keyStateChange, true); | |
} | |
var rawField = document.getElementById("raw"); | |
var messageField = document.getElementById("message"); | |
function updateView(){ | |
rawField.innerHTML = ""; | |
rawField.appendChild(document.createTextNode(morseMessage)); | |
rawField.scrollLeft = rawField.scrollWidth; | |
messageField.innerHTML = ""; | |
messageField.appendChild(document.createTextNode(demorse(morseMessage, morseTable))); | |
messageField.scrollLeft = messageField.scrollWidth; | |
}; | |
updateView(); | |
</script> | |
</body> | |
</html> |
Got this:
function(m,o,r){r=1;return (m+' ').replace(/([.-])( ?)/g,function(_,s,e){return(r=r*2-~(s+1),e?o.charAt(r*(r=1)):'')})}
and if you use .split('') on the dictionary, we can even omit .charAt()
in favour of []
and get this down to 112 bytes.
@atk: hmmm, your output is not the same... outputs multiple spaces instead of one.
If you want to filter multiple spaces, you can add " *" at the end of the regex. I took the input format literally - he wrote "is second whitespace, so this place is word boundary" - nothing in there about the 3 spaces in his example, otherwise it works perfectly.
function(m,o,r){r=1;return (m+' ').replace(/([.-])( ?) */g,function(_,s,e){return(r=r*2-~(s+1),e?o.charAt(r*(r=1)):'')})}
The usage of eval outside the replace statement instead of an anonymous function inside strikes me as really cool, though. Great idea, @subzey ! I will try to convert my version of the code to feature this concept and would like to see some documentation on this in our wiki page.
In this case I have the problem that the replacement of the input string becomes too complicated - if the handling would be without the double spaces, one could use
function(m,o,r){return eval("r=1;"+(m+' ').replace(/([.-])( ?) */g,'(r=r*2-~$1'+'1,"$2"?o.charAt(r*(r=1)):"")+')+'""')}
What do you think: would it be possible to reduce the replace-Callbacks to one using the regexp /([.-])([^.-]*)/? If I find the time, I will try this myself.