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

Reply via email to