如何写一个状态机来解决计数笑脸?

How to write a state machine to solve the Count the smiley faces?

我已经解决了问题Count the smiley faces:

Given an array (arr) as an argument complete the function countSmileys that should return the total number of smiling faces.

Rules for a smiling face:

  • Each smiley face must contain a valid pair of eyes. Eyes can be marked as : or ;
  • A smiley face can have a nose but it does not have to. Valid characters for a nose are - or ~
  • Every smiling face must have a smiling mouth that should be marked with either ) or D

No additional characters are allowed except for those mentioned.

Valid smiley face examples: :) :D ;-D :~) Invalid smiley faces: ;( :> :} :]

Example

countSmileys([':)', ';(', ';}', ':-D']);       // should return 2;
countSmileys([';D', ':-(', ':-)', ';~)']);     // should return 3;
countSmileys([';]', ':[', ';*', ':$', ';-D']); // should return 1;

Note

In case of an empty array return 0. You will not be tested with invalid input (input will always be an array). Order of the face (eyes, nose, mouth) elements will always be the same.

然后当我查看解决方案时,我发现很多人使用正则表达式。然后我想写一个状态机来实现正则表达式来解决这个问题。但是我失败了。这是我的代码:

function countSmileys(smileys) {
  let state = smileyHasValidEye;
  return smileys.filter(smiley => {
    for (let s of [...smiley]) {
      state = state(s);
    }
    return state === true;
  }).length;
}

function smileyHasValidEye(s) {
  if (s === ':' || s === ';') {
    return smileyHasValidNose;
  }
  return smileyHasValidEye;
}

function smileyHasValidNose(s) {
  if (s === '-' || s === '~') {
    return smileyHasValidMouth;
  }
  return smileyHasValidMouth(s);
}

function smileyHasValidMouth(s) {
  if (s === ')' || s === 'D') {
    return true;
  }
  return;
}

console.log(countSmileys([':)', ';(', ';}', ':-D']));

我得到的错误是:

state = state(s);
              ^

TypeError: state is not a function

然后我调试我的代码我发现程序没有进入smileyHasValidNose函数。那我也不知道是什么原因

问题是您并没有真正在笑脸之间重置 state。所以下一个笑脸状态将是 true ,你不能调用它(它不是函数)。

您可以为 state 使用局部变量,将其重置为第一个函数(第一步)。

function countSmileys(smileys) {
  let firstStep = smileyHasValidEye;
  return smileys.filter(smiley => {
    let state = firstStep;
    for (let s of [...smiley]) {
      state = state(s);
    }
    return state === true;
  }).length;
}

function smileyHasValidEye(s) {
  if (s === ':' || s === ';') {
    return smileyHasValidNose;
  }
  return smileyHasValidEye;
}

function smileyHasValidNose(s) {
  if (s === '-' || s === '~') {
    return smileyHasValidMouth;
  }
  return smileyHasValidMouth(s);
}

function smileyHasValidMouth(s) {
  if (s === ')' || s === 'D') {
    return true;
  }
  return;
}

console.log(countSmileys([':)', ';(', ';}', ':-D']));

但是,如果字符串中除了笑脸(或部分笑脸)之外还有其他内容,此代码将会出错。

如果它没有检测到笑脸,我会将 smileyHasValidMouth 更改为 return false。只是为了在这里更加一致...

function smileyHasValidMouth(s) {
  if (s === ')' || s === 'D') {
    return true;
  }
  return false;
}

如果发现不是函数的值,请调整循环以提前退出。

    for (let s of [...smiley]) {
      state = state(s);
      if(typeof state !== 'function') return state;
    }

function countSmileys(smileys) {
  let firstStep = smileyHasValidEye;
  return smileys.filter(smiley => {
    let state = firstStep;
    for (let s of [...smiley]) {
      state = state(s);
      if (typeof state !== 'function') return state;
    }
  }).length;
}

function smileyHasValidEye(s) {
  if (s === ':' || s === ';') {
    return smileyHasValidNose;
  }
  return smileyHasValidEye;
}

function smileyHasValidNose(s) {
  if (s === '-' || s === '~') {
    return smileyHasValidMouth;
  }
  return smileyHasValidMouth(s);
}

function smileyHasValidMouth(s) {
  if (s === ')' || s === 'D') {
    return true;
  }
  return false;
}

console.log(countSmileys([':~(', ':>', ':D', ':(', ':o>', ';)', ':)']));