www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Find a char among string (string.findAmong.char)

reply BoQsc <vaidas.boqsc gmail.com> writes:
I get an error when I try to find that letter is among alphabet.
 onlineapp.d(13): Error: template 
 `std.algorithm.searching.findAmong` cannot deduce function from 
 argument types `!()(immutable(char), immutable(string))`, 
 candidates are:
 /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(2694):      
 `findAmong(alias pred = "a == b", InputRange, ForwardRange)(InputRange seq,
ForwardRange choices)`
   with `pred = "a == b",
        InputRange = immutable(char),
        ForwardRange = string`
   must satisfy the following constraint:
 `       isInputRange!InputRange`
This is the code: You can run it at: https://run.dlang.io/is/5cvuUZ import std; void main() { alias alphabet = letters; char[26] letters = ['a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; string wordExample = "Book."; foreach (letter; wordExample){ if (letter.findAmong(alphabet)){ write("found"); } write(letter); } }
Jul 05
next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Monday, 5 July 2021 at 18:45:10 UTC, BoQsc wrote:
 I get an error when I try to find that letter is among alphabet.
 onlineapp.d(13): Error: template 
 `std.algorithm.searching.findAmong` cannot deduce function 
 from argument types `!()(immutable(char), immutable(string))`, 
 candidates are:
 /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(2694):      
 `findAmong(alias pred = "a == b", InputRange, ForwardRange)(InputRange seq,
ForwardRange choices)`
   with `pred = "a == b",
        InputRange = immutable(char),
        ForwardRange = string`
   must satisfy the following constraint:
 `       isInputRange!InputRange`
This is the code: You can run it at: https://run.dlang.io/is/5cvuUZ import std; void main() { alias alphabet = letters; char[26] letters = ['a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; string wordExample = "Book."; foreach (letter; wordExample){ if (letter.findAmong(alphabet)){ write("found"); } write(letter); } }
If you replace the findAmong call with `[letter].findAmong(alphabet)`, this works. Both arguments to findAmong need to be ranges; you're calling it here against an immutable(char). As it says in the error: ``` from argument types `!()(immutable(char), immutable(string))` ``` immutable(char) looks a lot like immutable(char)[], but the latter is a string and the former is just a singular char.
Jul 05
parent reply jfondren <julian.fondren gmail.com> writes:
On Monday, 5 July 2021 at 18:53:27 UTC, jfondren wrote:
 If you replace the findAmong call with 
 `[letter].findAmong(alphabet)`, this works.
Consider: ```d import std; void main() { import std.ascii : alphabet = letters; string wordExample = "Book."; foreach (letter; wordExample) { writefln!"%c is %sa letter"(letter, [letter].findAmong(alphabet).length ? "" : "not "); writefln!"%c is %sa letter"(letter, alphabet.canFind(letter) ? "" : "not "); } writeln("___>>___finally some letters".findAmong(alphabet)); } ```
Jul 05
parent reply BoQsc <vaidas.boqsc gmail.com> writes:
On Monday, 5 July 2021 at 18:59:09 UTC, jfondren wrote:
 On Monday, 5 July 2021 at 18:53:27 UTC, jfondren wrote:
 If you replace the findAmong call with 
 `[letter].findAmong(alphabet)`, this works.
Consider: ```d import std; void main() { import std.ascii : alphabet = letters; string wordExample = "Book."; foreach (letter; wordExample) { writefln!"%c is %sa letter"(letter, [letter].findAmong(alphabet).length ? "" : "not "); writefln!"%c is %sa letter"(letter, alphabet.canFind(letter) ? "" : "not "); } writeln("___>>___finally some letters".findAmong(alphabet)); } ```
If I use `[letter].findAmong(alphabet)` in my code, it considers a dot (.) punctuation character as a letter. You can see it here: https://run.dlang.io/is/YWmaXU
Jul 05
parent reply jfondren <julian.fondren gmail.com> writes:
On Monday, 5 July 2021 at 19:19:19 UTC, BoQsc wrote:
 If I use `[letter].findAmong(alphabet)` in my code, it 
 considers a dot (.) punctuation character as a letter.
 You can see it here:
 https://run.dlang.io/is/YWmaXU
It returns a zero-length array that, because it's not null, is true. That's why I used .length in my example. ``` $ rdmd --eval 'writeln("str"[$..$].length); writeln("str"[$..$] ? true : false)' 0 true $ rdmd --eval 'writeln([].length); writeln([] ? true : false)' 0 false ```
Jul 05
parent reply BoQsc <vaidas.boqsc gmail.com> writes:
On Monday, 5 July 2021 at 19:25:23 UTC, jfondren wrote:
 On Monday, 5 July 2021 at 19:19:19 UTC, BoQsc wrote:
 If I use `[letter].findAmong(alphabet)` in my code, it 
 considers a dot (.) punctuation character as a letter.
 You can see it here:
 https://run.dlang.io/is/YWmaXU
It returns a zero-length array that, because it's not null, is true. That's why I used .length in my example. ``` $ rdmd --eval 'writeln("str"[$..$].length); writeln("str"[$..$] ? true : false)' 0 true $ rdmd --eval 'writeln([].length); writeln([] ? true : false)' 0 false ```
Oh alright I think I fixed it with your guidance. ``` import std; void main() { alias alphabet = letters; char[26] letters = ['a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; string wordExample = "Book."; foreach (letter; wordExample){ if (([letter].findAmong(alphabet)).length){ write(letter); write(" letter is found among the alphabet."); writeln; } } } ``` But I really don't like how it looks less readable and makes less sense on first look. `if (([letter].findAmong(alphabet)).length)` I'd like to use some method on the `letter` instead of [] And `.length` does not make a lot of sense when reading like an english sentence.
Jul 05
parent reply jfondren <julian.fondren gmail.com> writes:
On Monday, 5 July 2021 at 19:34:14 UTC, BoQsc wrote:
 But I really don't like how it looks less readable and makes 
 less sense on first look.
 `if (([letter].findAmong(alphabet)).length)`
 I'd like to use some method on the `letter` instead of []
 And `.length` does not make a lot of sense when reading like an 
 english sentence.
I suggest canFind, like in my earlier example. findAmong is like "consume this range until you find one of these things, and then return the remainder of the range". It doesn't really fit your use.
Jul 05
parent reply BoQsc <vaidas.boqsc gmail.com> writes:
On Monday, 5 July 2021 at 19:48:13 UTC, jfondren wrote:
 On Monday, 5 July 2021 at 19:34:14 UTC, BoQsc wrote:
 But I really don't like how it looks less readable and makes 
 less sense on first look.
 `if (([letter].findAmong(alphabet)).length)`
 I'd like to use some method on the `letter` instead of []
 And `.length` does not make a lot of sense when reading like 
 an english sentence.
I suggest canFind, like in my earlier example. findAmong is like "consume this range until you find one of these things, and then return the remainder of the range". It doesn't really fit your use.
I tried out .canFind method, and to test it I removed the letter 'o' from the Alphabet. Weirdly enough .canFind method still found 'o' letter among the Alphabet. https://run.dlang.io/is/2Fvenf
Jul 06
parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 6 July 2021 at 11:35:14 UTC, BoQsc wrote:

 I tried out .canFind method, and to test it I removed the 
 letter 'o' from the Alphabet.
 Weirdly enough .canFind method still found 'o' letter among the 
 Alphabet.

 https://run.dlang.io/is/2Fvenf
Looks like it has something to do with the alias. Static arrays aren't ranges, so you should really be seeing the same error you would if you passed `letters` directly. Change the `canFind` call to take a slice of the array: ```d if (letters[].canFind(letter)){ ``` And it outputs the following as expected: ``` k letter is found among the alphabet. ``` This warrants a bug report with a minimized example.
Jul 06
prev sibling parent reply rassoc <rassoc rassoc.org> writes:
You can also do:

```d
import std;
void main()
{
     // https://dlang.org/phobos/std_ascii.html#.lowercase
     "Book.".filter!(c => lowercase.canFind(c))
            .each!(c => writeln(c, " found"));

     // Output:
     // o found
	// o found
	// k found
}
```
Jul 06
parent reply BoQsc <vaidas.boqsc gmail.com> writes:
On Tuesday, 6 July 2021 at 15:48:35 UTC, rassoc wrote:
 You can also do:

 ```d
 import std;
 void main()
 {
     // https://dlang.org/phobos/std_ascii.html#.lowercase
     "Book.".filter!(c => lowercase.canFind(c))
            .each!(c => writeln(c, " found"));

     // Output:
     // o found
 	// o found
 	// k found
 }
 ```
I really don't like reading arrow functions. It takes some more effort to understand, follow and get used to them. I'd like something simple and effortless looking and feeling that would make code readable similarly to an english sentence. Such as this, but as noted, this does not work as intended/assumed by me: ``` if (letter.findAmong(alphabet)){ write("found"); } ```
Jul 06
parent reply BoQsc <vaidas.boqsc gmail.com> writes:
I think nested foreach loops are more readable.

```
import std;
void main()
{
     alias alphabet = letters;
     char[26] letters = ['a','b', 'c', 'd', 'e',
                         'f', 'g', 'h', 'i', 'j',
                         'k', 'l', 'm', 'n', 'o',
                         'p', 'q', 'r', 's', 't',
                         'u', 'v', 'w', 'x', 'y', 'z'];

     string wordExample = "Book.";
	foreach (letter; wordExample){
         foreach (alphabetLetter; letters){
             if (letter == alphabetLetter) {
             	writeln(letter);
             }
         }
     	
     }
						
}
```
Jul 07
parent rassoc <rassoc rassoc.org> writes:
On Wednesday, 7 July 2021 at 12:22:11 UTC, BoQsc wrote:
 I think nested foreach loops are more readable.

 ```
 import std;
 void main()
 {
     alias alphabet = letters;
     char[26] letters = ['a','b', 'c', 'd', 'e',
                         'f', 'g', 'h', 'i', 'j',
                         'k', 'l', 'm', 'n', 'o',
                         'p', 'q', 'r', 's', 't',
                         'u', 'v', 'w', 'x', 'y', 'z'];

     string wordExample = "Book.";
 	foreach (letter; wordExample){
         foreach (alphabetLetter; letters){
             if (letter == alphabetLetter) {
             	writeln(letter);
             }
         }
     	
     }
 						
 }
 ```
Use whatever fits your style best or what you are most familar with. But be aware that there's a concise alternative: ```d import std; void main() { import std.ascii; // because there's also std.uni.isLower "Book.".filter!isLower.each!writeln; } ``` or alternatively with fully-qualified naming: ```d import std; void main() { "Book.".filter!(std.ascii.isLower).each!writeln; } ```
Jul 07