1

How can I get all possible strings in printable ASCII (eg. 0x20 () to 0x7E (~)) using a generator? It should output (if continually called with .next()):

 
!
"
#
$

...

~
  
 !
 "
 #
 $

and so on. How can I do this?

var gen = function * (){
    var counter = 0x20;
    while(true) yield String.fromCharCode(++counter);
};

works up to 94 tries (~). How I get this to work after that?

  • 3
    This sounds like homework. Could you show us what you've tried? – TankorSmash Jun 05 '17 at 18:37
  • 0x7E - 0x20 = 0x5E == 94 ;) – JustAndrei Jun 05 '17 at 18:42
  • Do you want it to start from the beginning after the last char? – JustAndrei Jun 05 '17 at 18:43
  • @JustAndrei no, after the `~` it starts with ` `, ` !`, and so on for all possible 2 char strings in printable ASCII. Then ` `, ` !`, and so on for all possible 3 char strings in printable ASCII, and so on. –  Jun 05 '17 at 18:44
  • 2
    It seems like expressing a number using radix 94 with digits from 0x20 to 0x7E – JustAndrei Jun 05 '17 at 18:48
  • @JustAndrei you are correct. –  Jun 05 '17 at 18:50
  • " and so on for all possible 3 char strings in printable ASCII, and so on." - so you want it to loop forever, eventually generating 1,000,000,000,000,... character strings? – Dave S Jun 05 '17 at 18:50
  • Might as well edit your question to include the exact homework question. – Dave S Jun 05 '17 at 18:51
  • @DaveS yes, if I do something like `var g = theGenerator(); while(true) {console.log(g.next())}`, then I should get all printable ASCII strings of any length after a while –  Jun 05 '17 at 18:51
  • 1
    You might use something like this https://stackoverflow.com/questions/14605096/change-base-of-a-number-in-javascript-using-a-given-digits-array in conjunction with your generator skeleton. – JustAndrei Jun 05 '17 at 18:52
  • For one thing, don't you need to tell your generator function how long the current string should be? 3 printable characters, or 1,000,000,000 printable characters? – Dave S Jun 05 '17 at 18:52
  • @DaveS no, it starts with all possible (printable ASCII) 1 char strings, than all possible (printable ASCII) 2 char strings... –  Jun 05 '17 at 18:53
  • Hint: you need some nested loops. – Dave S Jun 05 '17 at 19:03

2 Answers2

3

Here's a stab at it. As determined in the comments above, this is a matter of taking each number's base 94 representation and adding 32 and printing the corresponding ASCII characters. That's what the char function below does. The numbers generator function iterates from 0 to infinity, and the str function integer-divides the given number by 94 recursively, concatenating the remainders as characters (per char()) to produce a string.

function* numbers() {
  for (let i = 0;; i++) {
    yield str(i);
  }
}

function str(i) {
  if (i === 0) {
    return '';
  }
  return str(Math.floor(i / 94)) + char(i % 94);
}

function char(i) {
  return String.fromCharCode(i+32);
}

const gen = numbers();
setInterval(() => console.log(gen.next().value), 50);

If you'd rather have a single function, it might look like this:

function* numbers() {
  for (let i = 0;; i++) {
    let d = i; 
    let s = '';
    
    while (d > 0) {
      let r = d % 94;
      d = Math.floor(d / 94);
      s = String.fromCharCode(r+32) + s;
    }
    
    yield s;
  }
}

const gen = numbers();
setInterval(() => console.log(gen.next().value), 50);
Jordan Running
  • 102,619
  • 17
  • 182
  • 182
  • Thanks! At what point does integer overflow / float num limitations cause this to stop working? –  Jun 05 '17 at 19:10
  • Note to future visitors: you can replace the `32` with the char code of the start character and `94` with the difference between the start and end char for a different char set. –  Jun 05 '17 at 19:20
  • 1
    @User9123 The `str` function runs without error with both `Number.MAX_SAFE_INTEGER` (2^53 - 1) and `Number.MAX_VALUE` (≈1.79E+308), but I haven't taken the time to confirm that the output is *correct*. The generator function is as simple as can be so unless there's a bug in the JS engine I can't imagine it having any issue before then. – Jordan Running Jun 05 '17 at 19:23
1

I propose a recursive generator solution:

// Generate chars:
function* chars(from, to) {
  while (from <= to) yield String.fromCharCode(from++);
}

// Generate words from chars:
function* words(from, to) {
  yield* chars(from, to);
  for (let word of words(from, to)) {
    for (let char of chars(from, to)) {
      yield word + char;
    }
  }
}

// Example:
let w = words(0x20, 0x7E);
setInterval(() => console.log(w.next().value), 50);
le_m
  • 19,302
  • 9
  • 64
  • 74