March 04, 2022

On Thursday, 3 March 2022 at 20:23:14 UTC, forkit wrote:

>

On Thursday, 3 March 2022 at 19:28:36 UTC, matheus wrote:

>

I'm a simple man who uses D with the old C mentality:
[...]

    string s, str = "4A0B1de!2C9~6";
    foreach(i;str){
        if(i < '0' || i > '9'){ continue; }
        s ~= i;
    }

[...]

mmm..but we no longer live in simple times ;-)

(i.e. unicode)

If you look here, you'll see that it's already the same logic. If it were me I would have even written like this:

"4A0B1de!2C9~6".filter!(c =>
                        '0' <= c && c <= '9'
                       ).writeln; // 401296
March 03, 2022
On 3/3/22 13:03, H. S. Teoh wrote:

> 	string s = "blahblah123blehbleh456bluhbluh";

> 	assert(result == 123456);

I assumed it would generate separate integers 123 and 456. I started to implement a range with findSkip, findSplit, and friends but failed. :/

Ali

March 04, 2022

On Friday, 4 March 2022 at 02:36:35 UTC, Ali Çehreli wrote:

>

On 3/3/22 13:03, H. S. Teoh wrote:

>
string s = "blahblah123blehbleh456bluhbluh";
>
assert(result == 123456);

I assumed it would generate separate integers 123 and 456. I started to implement a range with findSkip, findSplit, and friends but failed. :/

Ali

It's called hit two targets with one arrow:

auto splitNumbers(string str)
{
  size_t[] n = [0];
  size_t i;
  foreach(s; str)
  {
    if(s >= '0' && s <= '9')
    {
      n[i] = 10 * n[i] + (s - '0');
    } else {
      i++;
      n.length++;
    }
  }
  return n.filter!(c => c > 0);
}

void main()
{
  auto s = "abc1234567890def1234567890xyz";
  s.splitNumbers.writeln; // [1234567890, 1234567890]
}

SDB@79

March 04, 2022

On Friday, 4 March 2022 at 02:36:35 UTC, Ali Çehreli wrote:

>

I assumed it would generate separate integers 123 and 456. I started to implement a range with findSkip, findSplit, and friends but failed. :/

I worked on it a little. I guess it's better that way. But I didn't think about negative numbers.

auto splitNumbers(string str) {
  size_t[] n;
  int i = -1;
  bool nextNumber = true;

  foreach(s; str)
  {
    if(s >= '0' && s <= '9')
    {
      if(nextNumber)
      {
        i++;
        n.length++;
        nextNumber = false;
      }
      n[i] = 10 * n[i] + (s - '0');
    }
    else nextNumber = true;
  }
  return n;

} unittest {

  auto n = splitNumbers(" 1,23, 456\n\r7890...");
  assert(n[0] == 1Lu);
  assert(n[1] == 23Lu);
  assert(n[2] == 456Lu);
  assert(n[3] == 7890Lu);
}

Presumably, D has more active and short possibilities. This is what I can do that making little use of the library.

Thank you...

SDB@79

March 04, 2022
On Friday, 4 March 2022 at 02:10:11 UTC, Salih Dincer wrote:
> On Thursday, 3 March 2022 at 20:23:14 UTC, forkit wrote:
>> On Thursday, 3 March 2022 at 19:28:36 UTC, matheus wrote:
>>>
>>> I'm a simple man who uses D with the old C mentality:
>>> [...]
>>> ```d
>>>     string s, str = "4A0B1de!2C9~6";
>>>     foreach(i;str){
>>>         if(i < '0' || i > '9'){ continue; }
>>>         s ~= i;
>>>     }
>>> ```
>>>[...]
>>
>> mmm..but we no longer live in simple times ;-)
>>
>> (i.e. unicode)
>
> If you look [here](https://github.com/dlang/phobos/blob/master/std/ascii.d#L315), you'll see that it's already the same logic. If it were me I would have even written like this:
> ```d
> "4A0B1de!2C9~6".filter!(c =>
>                         '0' <= c && c <= '9'
>                        ).writeln; // 401296
> ```

If you get this question at an interview, please remember to first ask whether it's ascii or unicode ;-)

" All of the functions in std.ascii accept Unicode characters but effectively ignore them if they're not ASCII." - https://github.com/dlang/phobos/blob/master/std/ascii.d

March 04, 2022

On Thursday, 3 March 2022 at 12:14:13 UTC, BoQsc wrote:

>

I need to check if a string contains integers,
and if it contains integers, remove all the regular string characters.
I've looked around and it seems using regex is the only closest solution.

import std.stdio;

void main(string[] args){

	if (args.length > 1){
	
		write(args[1]); // Needs to print only integers.
		
	} else {
		write("Please write an argument.");
	}
}

Regular expression solution

import std.stdio;
import std.regex;
import std.string: isNumeric;
import std.conv;

void main(string[] args){

	if (args.length > 1){
	
		writeln(args[1]); // Needs to print only integers.
		
		string argument1 = args[1].replaceAll(regex(r"[^0-9.]","g"), "");
		if (argument1.isNumeric){
			writeln(std.conv.to!uint(argument1));
		} else {
			writeln("Invalid value: ", args[1]," (must be int integer)");
		}
		
	} else {
		write("Please write an argument.");
	}
}
March 04, 2022

On Friday, 4 March 2022 at 07:55:18 UTC, forkit wrote:

>

If you get this question at an interview, please remember to first ask whether it's ascii or unicode 😀

auto UTFsample = `
1 İş 100€, 1.568,38 Türk Lirası
çarşıda eğri 1 çöp 4lınmaz!`;

UTFsample.splitNumbers.writeln; // [1, 100, 1, 568, 38, 1, 4]
March 04, 2022
On 3/3/22 04:14, BoQsc wrote:

> and if it contains integers, remove all the regular string characters.

Others assumed you wanted integer values but I think you want the digits of the integers. It took me a while to realize that chunkBy can do that:

// Convenience functions to tuple members of the result
// of chunkBy when used with a unary predicate.
auto isMatched(T)(T tuple) {
  return tuple[0];
}

// Ditto
auto chunkOf(T)(T tuple) {
  return tuple[1];
}

auto numbers(R)(R range) {
  import std.algorithm : chunkBy, filter, map;
  import std.uni : isNumber;

  return range
         .chunkBy!isNumber
         .filter!isMatched
         .map!chunkOf;
}

unittest {
  import std.algorithm : equal, map;
  import std.conv : text;

  // "٤٢" is a non-ASCII number example.
  auto r = "123 ab ٤٢ c 456 xyz 789".numbers;
  assert(r.map!text.equal(["123", "٤٢", "456", "789"]));
}

void main() {
}

isMatched() and chunkOf() are not necessary at all. I wanted to use readable names to fields of the elements of chunkBy instead of the cryptic t[0] and t[1]:

  return range
         .chunkBy!isNumber
         .filter!(t => t[0])   // Not pretty
         .map!(t => t[1]);     // Not pretty

Those functions could not be nested functions because otherwise I would have to write e.g.

  return range
         .chunkBy!isNumber
         .filter!(t => isMatched(t))   // Not pretty
         .map!(t => chunkOf(t));       // Not pretty

To get integer values, .to!int would work as long as the numbers consist of ASCII digits. (I am removing ٤٢.)

  import std.stdio;
  import std.algorithm;
  import std.conv;
  writeln("123 abc 456 xyz 789".numbers.map!(to!int));

Ali

March 04, 2022
On 3/4/22 01:53, Salih Dincer wrote:
> On Friday, 4 March 2022 at 07:55:18 UTC, forkit wrote:
>> If you get this question at an interview, please remember to first ask
>> whether it's ascii or unicode 😀
>
> ```d
> auto UTFsample = `
> 1 İş 100€, 1.568,38 Türk Lirası
> çarşıda eğri 1 çöp 4lınmaz!`;
>
> UTFsample.splitNumbers.writeln; // [1, 100, 1, 568, 38, 1, 4]
> ```

I think what forkit means is, should the function consider numbers made of non-ascii characters as well? For example, the ones on this page:

  https://www.fileformat.info/info/unicode/category/Nd/list.htm

Typical to any programming task, all of us made assumptions on what actually is needed. :)

Ali

March 04, 2022

On Friday, 4 March 2022 at 10:34:29 UTC, Ali Çehreli wrote:

>

[...]
isMatched() and chunkOf() are not necessary at all. I wanted to use readable names to fields of the elements of chunkBy instead of the cryptic t[0] and t[1]:

It's delicious, only four lines:

"1,2,3".chunkBy!(n => '0' <= n && n <= '9')
         .filter!(t => t[0])
         .map!(c => c[1])
         .writeln;

Thank you very much for this information sharing...

SDB@79