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.