This one is just a little tool that I sometimes like to use, when I have to go through a file and change the name of some array or similar. Granted, this can be done automatically through many text editors, but sometimes it's a hassle to even open a file, especially if it's biggish.
Besides, I found this bugger on my desktop today, in a slightly different form, and couldn't figure out what it was, that I wanted it to do (which is embarrassing, because it wasn't that hard). When I did figure out what it does, I decided to complicate it a bit, and use some of that fantastic functional paradigm, that Ocaml offers (lines 81, 84, and others).
I used a trick here, that I often use when doing functional programming. It's in the function on line 94 - handle_arguments. Inside this function I create a function with the same name. I can do this, because, unless I use the rec keyword during declaration, the function is not declared yet within itself. The inner function is recursive (the rec keyword), so that it can traverse a list and pass on the results, whilst the outer function calls it with proper arguments. Thanks to this, I don't have to remember to call handle_arguments with an additional parameter (an empty list for the results) from the outside, so the code is just that little bit cleaner.
Technical hints:
To compile the code just go:
ocamlc -o substitute str.cma substitute.ml
As you can see, it needs the additional Str module.
To run the program go:
ocamlc -o substitute str.cma substitute.ml
Oh yeah, and if you need a different format for the command line arguments, you can change the delimiter at line 28.
Warning: The substitution may fail somewhere, so if you try doing something important with this piece of software, better have a backup copy of whathever you're using it with.
The program:
1 (**
2 * Substitute
3 * Substitutes things for other things in files.
4 *
5 * Compiling:
6 * ocamlc -o substitute str.cma substitute.ml
7 * Example usage:
8 * echo '$0 $1!' | ./substitute '$0->Hello' '$1->world'
9 * #=> Hello world!
10 * Potential issues:
11 * May substitute more than you'd like, so keep a
12 * backup.
13 * Parameters:
14 * Each parameter is in the form of a placeholder,
15 * the delimiter '->' and a substitution
16 * (best to look at the example).
17 * Requires:
18 * Ocaml (http://caml.inria.fr/)
19 * Author:
20 * Konrad Siek
21 *)
22
23 (**
24 * Delimiter for program arguments.
25 * Establishes which part of the argument is the
26 * placeholder and which is the substitution.
27 *)
28 let delimiter = "->";;
29 (**
30 * Substitutes a placeholder with a phrase.
31 * This function runs recursivelly on a list.
32 * @param what - placeholder
33 * @param into - substitution
34 * @param contents - array of strings to traverse
35 * @return an array of strings
36 *)
37 let substitute functions contents =
38 let rec apply functions content =
39 match functions with
40 | transform::tail ->
41 apply tail (transform content)
42 | [] -> content
43 in
44 let result = ref [] in
45 let iterate element =
46 result := !result @
47 [apply functions element]
48 in
49 List.iter iterate contents;
50 !result
51 ;;
52 (**
53 * Outputs the contents of an array to standard
54 * output.
55 * @param contents - an array of strings
56 *)
57 let rec print_contents contents =
58 match contents with
59 | head::tail ->
60 print_endline head;
61 print_contents tail
62 | [] -> ()
63 ;;
64 (**
65 * Converts a program argument into a translation
66 * function.
67 * @param argument
68 * @return a function
69 *)
70 let handle_argument argument =
71 let regex = Str.regexp_string delimiter in
72 let bits = Str.split regex argument in
73 if List.length bits < 2 then (
74 prerr_string
75 ("Illegal argument: '" ^ argument ^ "'");
76 prerr_newline ();
77 fun input -> input
78 ) else (
79 let from = Str.regexp_string (List.hd bits) in
80 let into = List.fold_left
81 (fun a b -> a ^ delimiter ^ b)
82 (List.hd (List.tl bits))
83 (List.tl (List.tl bits)) in
84 fun input ->
85 (Str.global_replace from into input)
86 )
87 ;;
88 (**
89 * Converts a list of program arguments into a
90 * list of translation functions.
91 * @param arguments
92 * @return functions
93 *)
94 let handle_arguments arguments =
95 let rec handle_arguments arguments results =
96 match arguments with
97 | head::tail ->
98 let argument =
99 (handle_argument head) in
100 handle_arguments tail
101 (results @ [argument])
102 | [] -> results
103 in
104 handle_arguments arguments []
105;;
106(**
107 * Grab input from standard input - read until
108 * an end of stream occurs.
109 * @param unit
110 * @return list of strings
111 *)
112let read_input () =
113 let list = ref [] in
114 let _ = try
115 while true do
116 let line = input_line stdin in
117 list := !list @ [line]
118 done
119 with _ -> () in
120 !list
121;;
122
123(* Convert argument vector to list *)
124let arguments = (List.tl (Array.to_list Sys.argv)) in
125(* Translate arguments to functions *)
126let functions = handle_arguments arguments in
127(* Read contents from standard input *)
128let contents = read_input () in
129(* Apply transformations on contents *)
130let results = substitute functions contents in
131(* And print results to standard output *)
132print_contents results;;
2 * Substitute
3 * Substitutes things for other things in files.
4 *
5 * Compiling:
6 * ocamlc -o substitute str.cma substitute.ml
7 * Example usage:
8 * echo '$0 $1!' | ./substitute '$0->Hello' '$1->world'
9 * #=> Hello world!
10 * Potential issues:
11 * May substitute more than you'd like, so keep a
12 * backup.
13 * Parameters:
14 * Each parameter is in the form of a placeholder,
15 * the delimiter '->' and a substitution
16 * (best to look at the example).
17 * Requires:
18 * Ocaml (http://caml.inria.fr/)
19 * Author:
20 * Konrad Siek
21 *)
22
23 (**
24 * Delimiter for program arguments.
25 * Establishes which part of the argument is the
26 * placeholder and which is the substitution.
27 *)
28 let delimiter = "->";;
29 (**
30 * Substitutes a placeholder with a phrase.
31 * This function runs recursivelly on a list.
32 * @param what - placeholder
33 * @param into - substitution
34 * @param contents - array of strings to traverse
35 * @return an array of strings
36 *)
37 let substitute functions contents =
38 let rec apply functions content =
39 match functions with
40 | transform::tail ->
41 apply tail (transform content)
42 | [] -> content
43 in
44 let result = ref [] in
45 let iterate element =
46 result := !result @
47 [apply functions element]
48 in
49 List.iter iterate contents;
50 !result
51 ;;
52 (**
53 * Outputs the contents of an array to standard
54 * output.
55 * @param contents - an array of strings
56 *)
57 let rec print_contents contents =
58 match contents with
59 | head::tail ->
60 print_endline head;
61 print_contents tail
62 | [] -> ()
63 ;;
64 (**
65 * Converts a program argument into a translation
66 * function.
67 * @param argument
68 * @return a function
69 *)
70 let handle_argument argument =
71 let regex = Str.regexp_string delimiter in
72 let bits = Str.split regex argument in
73 if List.length bits < 2 then (
74 prerr_string
75 ("Illegal argument: '" ^ argument ^ "'");
76 prerr_newline ();
77 fun input -> input
78 ) else (
79 let from = Str.regexp_string (List.hd bits) in
80 let into = List.fold_left
81 (fun a b -> a ^ delimiter ^ b)
82 (List.hd (List.tl bits))
83 (List.tl (List.tl bits)) in
84 fun input ->
85 (Str.global_replace from into input)
86 )
87 ;;
88 (**
89 * Converts a list of program arguments into a
90 * list of translation functions.
91 * @param arguments
92 * @return functions
93 *)
94 let handle_arguments arguments =
95 let rec handle_arguments arguments results =
96 match arguments with
97 | head::tail ->
98 let argument =
99 (handle_argument head) in
100 handle_arguments tail
101 (results @ [argument])
102 | [] -> results
103 in
104 handle_arguments arguments []
105;;
106(**
107 * Grab input from standard input - read until
108 * an end of stream occurs.
109 * @param unit
110 * @return list of strings
111 *)
112let read_input () =
113 let list = ref [] in
114 let _ = try
115 while true do
116 let line = input_line stdin in
117 list := !list @ [line]
118 done
119 with _ -> () in
120 !list
121;;
122
123(* Convert argument vector to list *)
124let arguments = (List.tl (Array.to_list Sys.argv)) in
125(* Translate arguments to functions *)
126let functions = handle_arguments arguments in
127(* Read contents from standard input *)
128let contents = read_input () in
129(* Apply transformations on contents *)
130let results = substitute functions contents in
131(* And print results to standard output *)
132print_contents results;;
No comments:
Post a Comment