查找数组中的所有匹配项(字母)

时间:2018-06-15 10:38:25

标签: javascript reactjs

我想在React.js中创建一个刽子手游戏,当用户点击一个字母时,这个代码会搜索单词中的字母并显示她。当单词只包含一个相同的字母时,它可以正常工作。 我希望这段代码可以像“' PROGRAMMING'与2' M'。

handleChooseLetter = (index) => {

const usedWord = [...this.state.usedWord];

const chosenLetter = this.state.letters[index].letter;

var letterPosition = usedWord.indexOf(chosenLetter);

if (letterPosition >= 0) {
   hiddenWord.splice(letterPosition, 1, chosenLetter); 

   this.setState({hiddenWord: hiddenWord});
}

}

我已经尝试了一个while循环,但它在我的情况下不起作用:

var indices = [];

while(letterPosition >= 0) {
  const hiddenWord = [...this.state.hiddenWord];
  indices.push(letterPosition);
  letterPosition = usedWord.indexOf(chosenLetter, letterPosition + 1);
  hiddenWord.splice(letterPosition, 1, chosenLetter); 
  this.setState({hiddenWord: hiddenWord});
}

对我来说,结果就是找到这个字母,并在字母的最后一个字母处显示它们。

我认为我的问题在于拼接错误的letterPosition

拼接方法

这是我的chooseWord功能:

state = {
wordList: [
  { id: 1, word: 'PROGRAMMING'},
],
usedWord: [],
hiddenWord: [],
}

chooseWord() {
const wordList = [...this.state.wordList];

const listLength = wordList.length;

const randomWord = this.state.wordList[Math.floor(Math.random() * listLength)].word;

const splittedWord = randomWord.split("");

const arr = new Array(randomWord.length + 1).join("_").split("");

this.setState({
  usedWord: splittedWord, 
  hiddenWord: arr
});

}

3 个答案:

答案 0 :(得分:4)

最简单的方法是replace,不使用数组:

const usedWord = "programming";
const chosenLetter = "m";
const hiddenWord = usedWord.replace(new RegExp("[^" + chosenLetter + "]", "g"), "_");
console.log(hiddenWord);

当用户添加更多字母时,您可以将它们添加到字符类:

const usedWord = "programming";
const chosenLetters = "mp";
const hiddenWord = usedWord.replace(new RegExp("[^" + chosenLetters + "]", "g"), "_");
console.log(hiddenWord);

反应示例:

class Hangman extends React.Component {
    constructor(...args) {
        super(...args);
        this.state = {
            availableLetters: "abcdefghijklmnopqrstuvwxyz",
            chosenLetters: "",
            word: this.props.word
        };
        this.chooseLetter = this.chooseLetter.bind(this);
    }

    chooseLetter({target: {tagName, type, value}}) {
        if (tagName === "INPUT" && type === "button") {
            this.setState(prevState => ({chosenLetters: prevState.chosenLetters + value}));
        }
    }

    render() {
        const {word, chosenLetters} = this.state;
        const hiddenWord = word.replace(new RegExp("[^" + chosenLetters + "]", "g"), "_");
        return <div>
            <div>Word:&nbsp;&nbsp;&nbsp;<span className="hiddenWord">{hiddenWord}</span></div>
            <div onClick={this.chooseLetter} style={{marginTop: "8px"}}>
              {[...this.state.availableLetters].map(
                letter => <input type="button" value={letter} disabled={chosenLetters.includes(letter)} />
              )}
            </div>
          </div>;
    }
}

ReactDOM.render(
    <Hangman word="programming" />,
    document.getElementById("root")
);
.hiddenWord {
  font-family: monospace;
  letter-spacing: 1em;
  font-size: 18px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

对于单个英文字母,您不必担心使用new RegExp(chosenLetter, "g"),因为没有一个英文字母在正则表达式中具有特殊含义。如果您确实拥有具有特殊含义的字符(.$等),则在将字符传递给RegExp构造函数之前,您将转义该字符; see this question's answers了解如何做到这一点。

答案 1 :(得分:2)

我添加了字母输入<input onChange={this.handleChooseLetter} value={letter} />并更改了你的handleChooseLetter函数,如果找到至少1个字母,则迭代使用过的单词的字母(因为你的usedWord.indexOf(chosenLetter)总是只返回1个索引),所以我决定迭代整个单词并检查所选字母,如果该索引上的字母存在,我只是将该字母插入同一索引上的隐藏单词 - 因为隐藏和使用的单词具有相同的长度:

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      hiddenWord: "___________",
      usedWord: "PROGRAMMING",
      letter: ""
    };
  }

  handleChooseLetter = e => {
    const usedWord = [...this.state.usedWord];
    const chosenLetter = e.target.value.toLocaleUpperCase();

    let letterPosition = usedWord.indexOf(chosenLetter);

    if (letterPosition > -1) {
      this.setState(prevState => {
        const hiddenWord = [...prevState.hiddenWord];
        for (let i = 0; i < usedWord.length; i++) {
          if (usedWord[i] === chosenLetter) {
            hiddenWord[i] = chosenLetter;
          }
        }
        return { hiddenWord, letter: "" };
      });
      return;
    }
    this.setState({ letter: "" });
  };

  render() {
    const { hiddenWord, letter } = this.state;
    return (
      <div className="App">
        {[...hiddenWord].map((letter, index) => (
          <span key={index}>{letter}&nbsp;</span>
        ))}
        <input onChange={this.handleChooseLetter} value={letter} />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

答案 2 :(得分:-1)

啊哈!我曾经为我的班级做过类似的项目。下面是github回购供您参考: https://github.com/LordKriegan/WraithFood

基本上,我所做的是创建了一个包含多个字符串和一些函数的对象。当游戏加载时,它从我的列表中选择一个随机单词并设置2个字符串。一个是完整的单词(让我们称这个属性为fullWord),另一个基本上是一个长度相同的字符串,所有字母都转换为下划线(让我们称之为guessedWord,也可以在game.js中看到setWord()文件)。

但你有兴趣检查这些信件!多么容易。 Javascript字符串有一个名为.includes()的内置方法,它将一个字符串作为参数。因为我在对象中保存了我的单词,所以我只是用我要检查的字母在该单词上运行.includes(),然后如果它通过我的所有验证(已经猜到的字母,无论是否在字中,等),我用另一个名为.charAt(i)的String方法在guessedWord上运行了一个for循环。此方法只返回其调用的字符串中位置i的字符。由于我必须在我的对象中使用字符串,我知道它的长度相同,我可以在fullWord上执行for循环,检查位置i处的每个字母,然后使用.substr()重置guessedWord属性。此方法根据您传递的参数返回部分字符串。基本上我将guessedWord设置为+ +。这是游戏对象中的checkLet()函数。

我建议您阅读https://www.w3schools.com/js/js_string_methods.asp

上的字符串方法