digitalmars.D.learn - Decoding Pattern to a Tuple
- =?UTF-8?B?Tm9yZGzDtnc=?= (8/8) Feb 19 2016 Have anybody put together a generalised form of findSplit that
- =?UTF-8?Q?Ali_=c3=87ehreli?= (33/41) Feb 19 2016 The following toy program works with that particular case but can be
- =?UTF-8?Q?Ali_=c3=87ehreli?= (75/76) Feb 19 2016 Not ready for prime time but now it's templatized:
- =?UTF-8?B?Tm9yZGzDtnc=?= (2/5) Feb 22 2016 Thanks!
- Artur Skawina via Digitalmars-d-learn (28/41) Feb 22 2016 In practice, that isn't necessarily a good idea, because this kind
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)
Feb 19 2016
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
Feb 19 2016
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
Feb 19 2016
On Friday, 19 February 2016 at 22:16:10 UTC, Ali Çehreli wrote:On 02/19/2016 11:04 AM, Ali Çehreli wrote:Thanks!can be templatized:Not ready for prime time but now it's templatized:
Feb 22 2016
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
Feb 22 2016









=?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> 