| Thread overview | |||||||
|---|---|---|---|---|---|---|---|
|
February 19, 2016 Decoding Pattern to a Tuple | ||||
|---|---|---|---|---|
| ||||
Have anybody put together a generalised form of findSplit that can split and decode using a compile time parameters somewhat like
"(1)-(2.0)".decode!("(", int, ")", char, "(", double, ")")
evaluates to
to a
tuple!(int, char, double)
with value
tuple(1, '-', 2.0)
| ||||
February 19, 2016 Re: Decoding Pattern to a Tuple | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On 02/19/2016 10:10 AM, Nordlöw wrote: > Have anybody put together a generalised form of findSplit that can split > and decode using a compile time parameters somewhat like > > "(1)-(2.0)".decode!("(", int, ")", char, "(", double, ")") > > evaluates to > > to a > > tuple!(int, char, double) > > with value > > tuple(1, '-', 2.0) The following toy program works with that particular case but can be templatized: import std.stdio; import std.string; import std.regex; import std.typecons; import std.conv; auto decode(string s) { // Warning: Treats "012" as int (value 12), not octal (value 10). enum intClass = `[0-9]+`; enum charClass = `.`; // Found on the internet: enum floatClass = `[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?`; enum expr = format(`[(](%s)[)](%s)[(](%s)[)]`, intClass, charClass, floatClass); enum r = ctRegex!expr; auto matched = s.match(r); if (matched) { foreach (e; matched) { // We are ignoring potential other matches on the same line and // returning just the first match. (Of course, no loop is needed.) return tuple(e[1].to!int, e[2].to!char, e[3].to!double); } } return Tuple!(int, char, double)(); } void main() { auto t = decode("(1)-(2.5)"); writeln(t); } Ali | |||
February 19, 2016 Re: Decoding Pattern to a Tuple | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 02/19/2016 11:04 AM, Ali Çehreli wrote:
> can be templatized:
Not ready for prime time but now it's templatized:
import std.stdio;
import std.string;
import std.regex;
import std.typecons;
import std.conv;
import std.algorithm;
import std.range;
template regexClass(T) {
static if (is (T == int)) {
// Warning: Treats "012" as int (value 12), not octal (value 10).
enum regexClass = `[0-9]+`;
} else static if (is (T == char)) {
enum regexClass = `.`;
} else static if (is (T == double)) {
enum regexClass = `[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?`;
} else {
static assert(false, format("Unsupported type %s", arg));
}
}
string regexEscape(string s) {
// TODO: Expand the array and fix the logic.
enum specialRegexChars = [ '(', ')' ];
return s.map!(c => (specialRegexChars.canFind(c)
? format("[%s]", c)
: format("%s", c)))
.joiner
.text;
}
auto parseDecodeArgs(Args...)(string matchedElementName) {
string regexString;
string tupleString = "return tuple(";
size_t selectionId = 1;
foreach (arg; Args) {
static if (is (arg)) {
regexString ~= format("(%s)", regexClass!arg);
tupleString ~=
format("%s[%s].to!%s, ",
matchedElementName, selectionId, arg.stringof);
++selectionId;
} else static if (is (typeof(arg) == string)) {
regexString ~= regexEscape(arg);
} else {
static assert(false, format("Unsupported type %s", typeof(arg)));
}
}
tupleString ~= ");";
return tuple(regexString, tupleString);
}
auto decode(Args...)(string s) {
enum parseResult = parseDecodeArgs!Args("e");
enum r = ctRegex!(parseResult[0]);
// pragma(msg, parseResult[0]);
// pragma(msg, parseResult[1]);
auto matched = s.match(r);
if (matched) {
foreach (e; matched) {
mixin (parseResult[1]);
}
}
return typeof(return)();
}
void main() {
auto t = decode!("(", int, ")", char, "(", double, ")")("(1)-(2.5)");
writeln(t);
// Create a decoder for repeated use
auto decoder = (string s) => decode!(int, "/", double)(s);
// Decode each with the same decoder
auto decoded = ["1/1.5", "2/2.5", "3/3.5"]
.map!decoder;
writeln(decoded);
}
Ali
| |||
February 22, 2016 Re: Decoding Pattern to a Tuple | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Friday, 19 February 2016 at 22:16:10 UTC, Ali Çehreli wrote:
> On 02/19/2016 11:04 AM, Ali Çehreli wrote:
>
> > can be templatized:
>
> Not ready for prime time but now it's templatized:
Thanks!
| |||
February 22, 2016 Re: Decoding Pattern to a Tuple | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On 02/19/16 19:10, Nordlöw via Digitalmars-d-learn wrote: > Have anybody put together a generalised form of findSplit that can split and decode using a compile time parameters somewhat like > > "(1)-(2.0)".decode!("(", int, ")", char, "(", double, ")") > > evaluates to > > to a > > tuple!(int, char, double) > > with value > > tuple(1, '-', 2.0) In practice, that isn't necessarily a good idea, because this kind of project-local helpers add a level of obfuscation. But as the language is missing /real/ pattern-matching, this functionality is reinvented again and again. Here's a simple version that takes a single pattern string with the individual patterns placed between "{%" and "%}", and that doesn't support `char` directly (char can be easily gotten from the string). template decode(string P, alias S) { alias T(A...) = A; static if (P.length) { import std.algorithm, std.conv; enum PS = findSplit(P, `{%`); static assert (PS[0]==S[0..PS[0].length]); enum PE = findSplit(PS[2], `%}`); enum PP = findSplit(PE[2], "{%")[0]; enum SS = findSplit(S[PS[0].length..$], PP); alias decode = T!(mixin(`to!(`~PE[0]~`)(SS[0])`), decode!(PE[2][PP.length..$], SS[2])); } else alias decode = T!(); } enum a = decode!("({%int%}){%string%}({%double%})", "(1)-(2.0)"); pragma(msg, typeof(a)); pragma(msg, a); Just a POC hack; don't use as-is; does not support user defined types (it would have to be a mixin to be able to do that). artur | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply