On 14-Aug-11 10:44 PM, Jonathan M Davis wrote:
On Sunday, August 14, 2011 03:23:39 Jonathan M Davis wrote:
On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
Hi,
This program loops through a string until it finds a number and gives
the position of it.
The first assert works, but not the second one.
import std.algorithm;
void main() {
static bool isNumber( char input, char dummy ) {
if ( ( input>= '0'&& input<= '9' ) || input == '.' )
return true;
else
return false;
}
string str = "abc123";
assert( countUntil!( ( input, b ) {
if ( ( input>= '0'&& input<= '9' ) || input == '.' ) return
true;
else return false;
} )(str, 0) == 3 ); // works
assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
}
This is the error:
parse.d(15): Error: template instance
countUntil!(isNumber,string,string) does not match template declaration
countUntil(alias pred = "a == b",R1,R2) if
(is(typeof(startsWith!(pred)(haystack,needle))))
Okay. Several things here. One, don't ever declare an individual char. char
is a UTF-8 code unit, not a code point. And characters are code points.
ASCII characters only require one UTF-8 code unit, so they can be held in a
single char, but that's not true of characters in general. When dealing
with individual characters, always use dchar. So, if you're using foreach
for a string, use dchar as the iteration type. e.g.
foreach(dchar c; str) {...}
Youre code will be wrong if it iterates over char or wchar, since those
aren't full characters. And because of that, _all_ strings are ranges of
dchar, not char or wchar. So, the fact that you're using string instead of
dstring with a range-based function like countUntil is irrelevant. You're
still dealing with a range of dchars. So, isNumber should definitely be
taking dchars, not chars.
Two, don't pass 0 as a string. 0 is an int. _None_ of those countUntil calls
shouldn't be compiling at all. It's actually a bit disturbing thath the
first one compiles. It definitely looks like a bug. countUntil takes two
ranges with the same element type. 0 is not a range, let alone a range of
dchars. 0 shouldn't even really be used as a dchar, since 0 is an int, not
a character.
Third, you really shouldn't be using if statements like that. It looks like
you don't know what you're doing if you do
if(condition)
return true;
else
return false;
The condition is already a bool. You can simply do
return condition;
Plenty of newbie programmers make that mistake, and I don't know how
experienced a programmer you are, but I'd advise you not to do that anymore.
In any case, I'm a bit shocked that the first call to countUntil compiles,
let alone works. That's quite disturbing actually. It looks like countUntil
has a bug. However, your usage of countUntil here does imply that it could
use an overload which takes a unary function and only one range.
Okay. countUntil is _supposed_ to be able to take a single value as its second
argument. However, the names for the templated types implied that it took a
range for its second value (it could take either a range or just an element,
just so long as startsWith(haystack, needle) compiles). So, that may need some
clarifying in the documentation. I misread it.
In any case, if you change isNumber to two dchars, your code will work. The
problem you're having is because a string is a range of dchars, not chars. But
still, you probably shouldn't be passing 0. Apparently, the compiler is doing
an implicit conversion from int to dchar to allow it to work, but it's
generally better to not do that.
- Jonathan M Davis
Hi,
Thanks Jonathan for your help. I've taken the things you've said on board.
I think I'm getting some where with D. I also mean to work more at C# too.
So this works:
import std.algorithm;
bool isNumber( dchar chr, dchar dummy ) {
return ( ( chr >= '0' && chr <= '9' ) || chr == '.' || chr == '-' ||
chr == '+' || chr == '"' );
}
void fun() {
dchar dummy = '\0';
auto indexEnd = countUntil!( isNumber )( input, dummy );
}
- Joel