Execute a Markov algorithm: Difference between revisions
Content added Content deleted
(Add Déjà Vu example) |
(Added OCaml solution) |
||
Line 2,059: | Line 2,059: | ||
Under the rules of left 4 registers, under the word has 8 character cells, the alphabet of the digits from 1 to 8. Rules are placed in "123,456", where "123" is a fragment, and "456" is to be replaced, in the registers of the РA to РD. The number of rules is stored in Р0, the initial word is in Р9. Number triggered rule is the last digit registration Р4 (0 to 3), if no rule did not work, the indicator 0, otherwise the current word to be processed. In РE is stored 10. |
Under the rules of left 4 registers, under the word has 8 character cells, the alphabet of the digits from 1 to 8. Rules are placed in "123,456", where "123" is a fragment, and "456" is to be replaced, in the registers of the РA to РD. The number of rules is stored in Р0, the initial word is in Р9. Number triggered rule is the last digit registration Р4 (0 to 3), if no rule did not work, the indicator 0, otherwise the current word to be processed. In РE is stored 10. |
||
=={{header|OCaml}}== |
|||
I'm not familiar with string processing, or parsing, so there are probably better ways to express this in OCaml. One might be with the mikmatch library which allows pattern-matching with regexps. Here I've only used the OCaml stdlib... |
|||
<lang OCaml>(* Useful for resource cleanup (such as filehandles) *) |
|||
let try_finally x f g = |
|||
try let res = f x in g x; res |
|||
with e -> g x; raise e |
|||
(* Substitute string 'b' for first occurance of regexp 'a' in 's'; |
|||
* Raise Not_found if there was no occurance of 'a'. *) |
|||
let subst a b s = |
|||
ignore (Str.search_forward a s 0); (* to generate Not_found *) |
|||
Str.replace_first a b s |
|||
(* At their simplest, modules can function like namespaces... though they're much more. *) |
|||
module Markov = struct |
|||
let parse_rules cin = |
|||
let open Str in |
|||
let rule = regexp "\\(.+\\)[ \t]+->[ \t]+\\(.*\\)" in |
|||
let leader s c = String.length s > 0 && s.[0] = c in |
|||
let parse_b s = if leader s '.' then (string_after s 1,true) else (s,false) in |
|||
let rec parse_line rules = |
|||
try |
|||
let s = input_line cin in |
|||
if leader s '#' then parse_line rules |
|||
else if string_match rule s 0 then |
|||
let a = regexp_string (matched_group 1 s) in |
|||
let b,terminate = parse_b (matched_group 2 s) in |
|||
parse_line ((a,b,terminate)::rules) |
|||
else failwith ("parse error: "^s) |
|||
with End_of_file -> rules |
|||
in List.rev (parse_line []) |
|||
let rec run rules text = |
|||
let rec apply s = function |
|||
| [] -> s |
|||
| (a,b,term)::next -> |
|||
try |
|||
let s' = subst a b s in |
|||
if term then s' else run rules s' |
|||
with Not_found -> apply s next |
|||
in apply text rules |
|||
end |
|||
let _ = |
|||
if Array.length Sys.argv <> 2 then |
|||
print_endline "Expecting one argument: a filename where rules can be found." |
|||
else |
|||
let rules = try_finally (open_in Sys.argv.(1)) Markov.parse_rules close_in in |
|||
(* Translate lines read from stdin, until EOF *) |
|||
let rec translate () = |
|||
print_endline (Markov.run rules (input_line stdin)); |
|||
translate () |
|||
in try translate () with End_of_file -> ()</lang> |
|||
With the above compiled to an executable 'markov', and the five rule-sets in files, strings are accepted on stdin for translation: |
|||
<pre> |
|||
<~/rosetta$> markov rules1 |
|||
I bought a B of As from T S. |
|||
I bought a bag of apples from my brother. |
|||
<~/rosetta$> markov rules2 |
|||
I bought a B of As from T S. |
|||
I bought a bag of apples from T shop. |
|||
<~/rosetta$> markov rules3 |
|||
I bought a B of As W my Bgage from T S. |
|||
I bought a bag of apples with my money from T shop. |
|||
<~/rosetta$> markov rules4 |
|||
_1111*11111_ |
|||
11111111111111111111 |
|||
<~/rosetta$> markov rules5 |
|||
000000A000000 |
|||
00011H1111000 |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |