Random D geekout
Denis Shelomovskij
verylonglogin.reg at gmail.com
Thu Apr 19 21:44:06 PDT 2012
20.04.2012 8:06, H. S. Teoh написал:
> I'm writing some code that does some very simplistic parsing, and I'm
> just totally geeking out on how awesome D is for writing such code:
>
> import std.conv;
> import std.regex;
> import std.stdio;
>
> struct Data {
> string name;
> string phone;
> int age;
> ... // a whole bunch of other stuff
> }
>
> void main() {
> Data d;
> foreach (line; stdin.byLine()) {
> auto m = match(line, "(\w+)\s+(\w+)");
It's better not to create a regex every iteration. Use e.g.
---
auto regEx = regex(`(\w+)\s+(\w+)`);
---
before foreach. Of course, you are not claiming this as a
high-performance program, but creating a regex every iteration is too
common mistake to show such code to newbies.
> if (!m) continue;
>
> auto key = m.captures[1];
One `.idup` here will be better. (sorry, just like to nitpick)
> auto value = m.captures[2];
>
> alias void delegate(string key, string value) attrDg;
> attrDg[string] dgs = [
> "name": delegate(string key, string value) {
> d.name = value;
> },
> "phone": delegate(string key, string value) {
> d.phone = value;
> },
> "age": delegate(string key, string value) {
> d.age = to!int(value);
> },
> ... // whole bunch of other stuff to
> // parse different attributes
> ];
> attrDg errordg = delegate(string key, string value) {
> throw Exception("Invalid attribute '%s'"
> .format(key));
> };
>
> // This is pure awesomeness:
> dgs.get(key.idup, errordg)(key.idup, value.idup);
> }
> // ... do something with Data
> }
>
> Basically, I use std.regex to extract keywords from the input, then use
> an AA to map keywords to code that implement said keyword. That AA of
> delegates is just pure awesomeness. AA.get's default value parameter
> lets you process keywords and handle errors with a single AA lookup. I
> mean, this is even better than Perl for this kind of text-processing
> code!
>
> The only complaint is that I couldn't write auto[string] dgs and have
> the compiler auto-infer the delegate type. :-) Additionally, I wasn't
> sure if I could omit the "delegate(string,string)" after each keyword;
> if that's actually allowed, then this would make D totally pwn Perl!!
A shorter variant:
---
void delegate(string, string)[string] dgs = [
"name" : (key, value) { d.name = value; },
"phone": (key, value) { d.phone = value; },
"age" : (key, value) { d.age = to!int(value); },
... // whole bunch of other stuff to
// parse different attributes
];
// `delegate` is needed because otherwise `errordg` will be inferred
// as a `function`, not `delegate` and `dgs.get` will fail
auto errordg = delegate(string key, string value) {
throw new Exception("Invalid attribute '%s'"
.format(key));
};
---
>
> (I left out some stuff that makes this code even more of a joy to write:
> using nested try/catch blocks, I can throw exceptions from deep-down
> parsing code and have the loop that loops over input lines automatically
> prefix error messages with the filename/line number where the error
> occurred. This way, even errors thrown by to!int() will be formatted
> nicely. With Perl, this gets extremely messy due to its pathological use
> of $. for line numbers which can get overwritten in unexpected places if
> you're processing more than one file at a time.)
>
> Did I mention I'm totally in love with D?? Seriously. It can handle
> system-level code and "high-level" text-processing code with total
> impunity. What's there not to like?!
>
>
> T
>
--
Денис В. Шеломовский
Denis V. Shelomovskij
More information about the Digitalmars-d
mailing list