Skip to content

Instantly share code, notes, and snippets.

@subzey
Forked from 140bytes/LICENSE.txt
Created July 8, 2011 14:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save subzey/1072010 to your computer and use it in GitHub Desktop.
Save subzey/1072010 to your computer and use it in GitHub Desktop.
deMorse: Morse code → text

deMorse

Translates Morse code into readable text using conversion dictionary.

Usage

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 <subzey@immelman.ru>
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>
@atk
Copy link

atk commented Jul 8, 2011

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.

@atk
Copy link

atk commented Jul 10, 2011

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.

@jed
Copy link

jed commented Jul 10, 2011

@atk: hmmm, your output is not the same... outputs multiple spaces instead of one.

@atk
Copy link

atk commented Jul 10, 2011

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)):'')})}

@atk
Copy link

atk commented Jul 10, 2011

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.

@atk
Copy link

atk commented Jul 10, 2011

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)):"")+')+'""')}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment