Kurz: Günther, Winfried, Dirk
Perl wird seiner Rolle als knappe Programmiersprache einmal mehr gerecht: Gleich drei Lösungen teilen sich den ersten Platz bei der Programmlänge. Die Programme "Günther" (Nr. 35), "Winfried" (Nr. 33) und "Dirk" (Nr. 41) benötigen nur 17 Zeilen Code für die Aufgabe (siehe Listings 1, 2 und 3, teilweise gekürzt).
Zudem bügelten die Perl-Freunde die Schmach, die einige in der langen Laufzeit der Expertenlösung sahen, wieder aus. Deren Autor Randal L. Schwartz hatte allerdings auch explizit den Auftrag erhalten, seine Lieblingssprache stilistisch vorzustellen, und nicht sein Programm auf Leistung zu trimmen. Das erledigten die drei Perl-Skripte im Testfeld, von denen das schnellste kaum ein Zehntel der Laufzeit der ersten Perl-Lösung benötigte. Alle drei verfolgen einen ähnlichen Ansatz und kommen mit einfachen Datenstrukturen aus. Der Ruf der Skriptsprache ist wieder hergestellt.
Schnell: Rörd, Helmut, Christoph
Die schnellsten Lösungen benutzen Compilersprachen - was niemanden überrascht. Verwundert hat aber doch, dass die Ocaml-Variante "Rörd" allen anderen den Rang ablief (Nr. 50, Listing 4). Die Sprache, die objektorientierte und funktionale Elemente vereint, hatte ihre Qualitäten schon bei mehreren Programmierwettbewerben bewiesen.
Auch auf C++ hatten einige in der Redaktion gewettet. Tatsächlich ist "Christoph" (Nr. 19, Listing 5) nur eine gute Sekunde langsamer als die Ocaml-Lösung. Das Programm nutzt neben der Bibliothek "Perl Compatible Regular Expression" nur reines C++ und schafft es damit auf Platz drei.
Für eine weitere Überraschung sorgte das Java-Programm "Helmut" (Nr. 18): Es war eine Spur schneller als die C++-Variante, benötigt dafür jedoch 365 Programmzeilen. Um das Ergebnis zu erreichen, wählte der Autor einen Mittelweg zwischen objektorientiertem Programmierstil und konkreter, datennaher Implementierung. So besteht sein Code aus fünf Klassen, darunter ein abstraktes Interface und zwei alternative Umsetzungen für die Sortierstrategie. Im Gegensatz zu vielen anderen Lösungen benutzt er jedoch keine Regular Expressions, um über den Text zu iterieren. Vielmehr lädt er Textstücke in Eingabebuffer und bearbeitet diese zeichenweise. Dabei hält er die Verwaltungsstrukturen einfach in einem Hash.
01 let sep_line = "@footnote:"
02 let ref_regexp = Str.regexp "\[\([0-9]+\)\]"
03
04 let ref_of_int n="[" ^ string_of_int n ^ "]"
05
06 let output_endline c s = output_string c s; output_char c 'n'
07
08 exception End_of_body
09
10 (* read body from inc, substitute references from table refs. If not in refs, evaluate unknown_ref; print to outc *)
11 let process_body inc outc refs unknown_ref =
12 let sub_ref l _ =
13 let old_n = int_of_string (Str.matched_group 1 l) in
14 try ref_of_int (Hashtbl.find refs old_n)
15 with Not_found -> unknown_ref old_n
16 in
17 try
18 while true do
19 let l = input_line inc in
20 if l = sep_line then raise End_of_body;
21 output_endline outc
22 (Str.global_substitute ref_regexp (sub_ref l) l)
23 done
24 with End_of_body -> output_endline outc sep_line
25
26 (* read foots from inc, process lines *)
27 let process_foots inc process_foot malformed_foot =
28 try
29 while true do
30 let l = input_line inc in
31 if Str.string_match ref_regexp l 0 then
32 process_foot l (int_of_string (Str.matched_group 1 l))
33 else malformed_foot l
34 done
35 with End_of_file -> ()
36
37 (* insert a new reference for old_n into refs and return the new n *)
38 let insert_ref refs old_n =
39 let n = Hashtbl.length refs + 1 in
40 Hashtbl.add refs old_n n;
41 n
42
43 (* reorder foots by appearance in body *)
44 let renumber_by_body inc outc =
45 let refs = Hashtbl.create 1000000 in
46 let new_ref old_n = ref_of_int (insert_ref refs old_n) in
47 process_body inc outc refs new_ref;
48 let foots = Array.make (Hashtbl.length refs) None in
49 let add_foot l old_n =
50 try
51 let n = Hashtbl.find refs old_n in
52 foots.(n-1) <- Some (Str. string_after l (Str.match_end ()))
53 with
54 Not_found -> prerr_endline ("unreferenced footnote: " ^ l)
55 and prerr_malformed l = prerr_endline ("malformed footnote: " ^ l) in
56 process_foots inc add_foot prerr_malformed;
57 for i = 1 to Array.length foots do
58 output_string outc (ref_of_int (i));
59 match foots.(i-1) with
60 None -> output_endline outc "Missing"
61 | Some l -> output_endline outc l
62 done
63
64 (* renumber references by original order *)
65 let renumber_by_foots inc outc =
66 while input_line inc<>sep_line do () done;
67 let refs = Hashtbl.create 1000000 in
68 let add_foot_ref _ old_n =
69 if not (Hashtbl.mem refs old_n) then ignore (insert_ref refs old_n)
70 in
71 process_foots inc add_foot_ref ignore;
72 seek_in inc 0;
73 process_body inc outc refs (function _ -> "[?]");
74 let print_foot l old_n =
75 let n = Hashtbl.find refs old_n in
76 output_string outc (ref_of_int n);
77 output_endline outc (Str.string_after l (Str.match_end ()))
78 in
79 process_foots inc print_foot (output_endline outc)
80
81 (* renumber footnote references *)
82 let renumber by_foots =
83 if by_foots then renumber_by_foots else renumber_by_body
84
85 (* process options and input files *)
86 let main () =
87 if Array.length Sys.argv > 1 then
88 let by_foots = ref false in
89 let do_file f =
90 let c = open_in f in
91 (try renumber !by_foots c stdout with e -> close_in c; raise e);
92 close_in c
93 in
94 Arg.parse [("-f", Arg.Set by_foots,
95 "Renumber by original order")]
96 do_file "Usage: footnotes [OPT] [file]"
97 else renumber_by_body stdin stdout;;
98 main ()
|
01 #include <fstream>
02 #include <iostream>
03 #include <pcrecpp.h>
04 #include <tr1/unordered_map>
05
06 pcrecpp::RE re_ref("^\[(\d+)\]");
07 pcrecpp::RE re_txt("(.*?)\[(\d+)\]");
08
09 void process(char const * filename) {
10 std::ifstream file(filename);
11 std::string line;
12 while (getline(file, line) and
13 line != "@footnote:");
14 std::tr1::unordered_map<int, int> dict;
15 int counter = 1;
16 while (getline(file, line)) {
17 int number = -1;
18 if (re_ref.PartialMatch(line, &number))
19 dict[number] = counter++;
20 }
21
22 file.clear(); file.seekg(0);
23 while (getline(file, line)) {
24 pcrecpp::StringPiece input(line);
25 pcrecpp::StringPiece prefix;
26 int ref;
27 while (re_txt.
28 Consume(&input,&prefix,&ref))
29 std::cout << prefix << "[" <<
30 (dict[ref] ? dict[ref] : ref) << "]";
31 std::cout << input << "n";
32 }
33 }
34
35 int main(int argc, char **argv) {
36 std::ios::sync_with_stdio(false);
37 for (int i = 1; i != argc; ++i)
38 process(argv[i]);
39 }
|
| Whitepaper |
|
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele
Über die letzten Jahre hinweg haben sich Open Source Lösungen als fester Bestandteil des gesamten Datenintegrationsmarktes etabliert. Viele Unternehmen haben bereits das Open Source Modell für Ihre Datenintegrationsprojekte aufgegriffen. Das vorliegende White Paper illustriert anhand ausgewählter Fallstudien und Anwendungsbeispiele die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.
Download PDF (Registrierung erforderlich)
|
|
The Role of Open Source in Data Integration
Obwohl in den letzten Jahren viele technische Fortschritte erzielt werden konnten, verfügen die meisten Datenintegrationsprozesse nach wie vor nur über eine sehr begrenzte Automatisierung. Das vorliegende White Paper von dem Industry Analyst Mark Madson wird zunächst ein grundlegendes Verständnis von Daten Integration vermitteln, die Vorzüge von Open Source Lösungen für Daten Integration erläutern und Ihnen professionelle Empfehlungen geben, damit Sie Ihre Integrationsjobs noch einfacher und produktiver gestalten können.
Download PDF (Registrierung erforderlich)
|
Dieser Online-Artikel kann Links enthalten, die auf nicht mehr vorhandene Seiten verweisen. Wir ändern solche "broken links"
nur in wenigen Ausnahmefällen. Der Online-Artikel soll möglichst unverändert der gedrucken Fassung entsprechen.
|
hypnos,
20.11.2008 18:32
hypnos,
20.11.2008 18:31