【问题标题】:Find difference between an array of strings and a string made from that array - React Native查找字符串数组和由该数组组成的字符串之间的区别 - React Native
【发布时间】:2021-09-11 02:37:08
【问题描述】:

所以这是我面临的一个有趣的问题。我有一个从 ASR 服务器接收到的数组,格式类似于 [{start: 0, end: 0.4, word: "Hello"}, {start: 0.4, end: 0.6, word: "my"}, {start: 0.6, end: 1, word: "name"}]。然后将该数组映射到仅包含单词的字符串数组,例如["Hello", "my", "name"] 最后使用.join(" ") 将该数组转换为字符串,从而生成类似"Hello my name" 的字符串。

问题在于尝试编辑这些值并保持原始数组的格式。我正在使用 React Native TextInput 来允许编辑字符串值。

假设用户想要更改

“你好,我的名字”

“你好,我叫”

“大声喊出我的名字”

在第一种情况下,需要将数组调整为[{start: 0, end: 0.4, word: "Hello"}, {start: 0.4, end: 0.6, word: "my"}, {start: 0.6, end: 1, word: "name is"}],在第二种情况下,必须将数组调整为[{start: 0, end: 0.4, word: "Bellow"}, {start: 0.4, end: 0.6, word: "my"}, {start: 0.6, end: 1, word: "name"}]

我完全不知道应该如何处理这个问题。我已经做了大约两个星期了,但仍然不知道。我最近的尝试是映射原始数组,将每个项目的单词值与同一索引处已编辑字符串的单词进行比较。如果它们匹配,我会将它们添加到最终数组中,如果不匹配,我将检查编辑后的字符串中的值是否与我从 Lodash.js 中的 .difference() 函数获得的更改之一匹配。我可能解释得不好,请看一下代码。

  const [value, setValue] = useState('');

  const findChanges = () => {

    let finalWords = [];
    // Each of the elements in the currentWords array has three properties: start, end, word
    let currentWords = data.words;
    if (!Array.isArray(currentWords)) currentWords = JSON.parse(data.words);
    // Extract only word strings from currentWords
    let currentArr = currentWords.map(x => x.word);
    let newArr = value.split(' ');
    let currentChangeEndsAt = undefined;

    let diff = difference(newArr, currentArr);

    const addToFinal = (text: string, startIndex: number, endIndex: number) => {
      if (startIndex === endIndex) {
        return finalWords.push({ ...currentWords[startIndex], word: text });
      }
      let start = currentWords[startIndex].start;
      let end = currentWords[endIndex].end;
      return finalWords.push({ start, end, word: text });
    };

    currentArr.forEach((word, index) => {
      // If index is smaller then we have already handled this word, skip
      if (currentChangeEndsAt > index) {
        return;
      }
      // If currentArr item at index matches newArr item at same index, add word to final
      if (word === newArr[index]) {
        return addToFinal(word, index, index);
      }
      // If currentArr item at index is one of the the differences
      if (diff.indexOf(word) !== -1) {
        // Determine recursively at which index the change ends
        const changeEndsAt = (searchIndex): number => {
          // If next word in currentArr matches the word in newArr at searchIndex return searchIndex
          // Else add 1 to searchIndex and recursively call the func again
          if (currentArr[index + 1] === newArr[searchIndex]) {
            return searchIndex;
          } else if (searchIndex === newArr.length - 1) {
            return searchIndex;
          } else {
            return changeEndsAt(searchIndex + 1);
          }
        };
        // Get substring of the change
        const endsAt = changeEndsAt(index + 1);
        const changeString = newArr.slice(index, endsAt).join(' ');
        const endIndex =
          endsAt > currentWords.length - 1 ? currentWords.length - 1 : endsAt;
        return addToFinal(changeString, index, endIndex);
      }
    });
    return finalWords;
  };

正如您所看到的,它非常混乱,您可能会说由于某些原因它无法正常工作。原因之一是如果在字符串函数的开头添加了一个单词,就会崩溃。我曾想过可能实现一个 onChangeText 处理程序,并可能使用 onSelectionChange 回调将 TextInput 的当前光标位置设置为状态,但我无法弄清楚我将如何从那里开始。如果有人对我如何处理这个甚至从哪里开始有任何指示,那将有很大帮助。对于冗长的问题和模糊的标题,我深表歉意,我愿意接受有关改进两者的建议。如果您有更好的想法,请在下面评论。提前致谢。

【问题讨论】:

  • 如果将句子修改为简单的“Hello”,您期望得到什么输出?
  • 嗨@Gershy,这也是它变得复杂的地方。那么预期的输出将是[{start: 0, end: 1, word: "Hello"}]。由于录音是固定长度的,因此必须调整开始和结束时间以适应文本。

标签: javascript arrays react-native lodash react-native-textinput


【解决方案1】:

如果我理解正确,您可以简单地将字符串拆分为组件;第一个组件与{ start: 0, end: 0.4 } 组合,第二个组件与{ start: 0.4, end: 0.6 } 组合,第二个组件以外的所有组件由空格连接并与{ start: 0.6, end: 1 } 组合。

let inp = document.querySelector('input');
let code = document.querySelector('code');

let fn = () => {
  
  let input = inp.value;
  let [ cmp1='', cmp2='', ...cmps ] = input.split(' ');
  let output = [
    { start: 0, end: 0.4, word: cmp1 },
    { start: 0.4, end: 0.6, word: cmp2 },
    { start: 0.6, end: 1, word: cmps.join(' ') }
  ];
  code.textContent = ''
    + '[\n'
    + output.map(item => '  ' + JSON.stringify(item)).join(',\n')
    + '\n]'
  
};
inp.addEventListener('input', fn);
fn();
code { white-space: pre; }
<p>Edit this text:</p>
<input value="Hello my name"/><br/>
<code></code>

我不确定我是否完全理解您的问题。如果这不是您想要的,请给出一个产生无效输出的输入示例,以及该场景中的正确输出应该是什么。

【讨论】:

  • 这种方法很有趣,但还不够稳健。看到 ASR 服务器可能会完全误解,与用户的预期输出相比,阵列的大小可能不正确。最终,我需要一种方法来确定用户编辑了哪些单词,以便我可以将它们的更改与输出时序值对齐。因此,在这种情况下,为了论证,假设预期输出为"He yelled something so lame"(我知道它在语音上没有意义),编辑将是[{start: 0, end: 0.4, word: "He yelled"}, {... word: "something"}, {... word: "lame"}]
  • 用户可以在任何索引处进行编辑,并且编辑可以是任何长度,因此如果原始数组在索引 x 处仅包含一个单词,则用户可以再添加 4 个单词并且函数必须是只能将此编辑添加到适用的数组项。希望这是有道理的
  • 嗯,我认为您要查找的内容定义不明确。如果用户将“Hello my name”编辑为“Hello my nice name”,“my”变成了“my nice”,还是“name”变成了“nice name”?答案是,我们永远无法知道;它没有明确定义(人工智能可以猜测,但它永远不会超过猜测)。为什么不改变用户使用的 ui,让 3 个输入框彼此内联呢?这样用户就可以指出他们正在更改哪个术语。
  • 从用户体验的角度来看,这是我的问题,这是不可能的。
  • 不幸的是,听起来您的问题没有解决方案 :) 您能否详细解释一下您的整个应用程序?这些带有startend 属性的数据的用途是什么?也许在更高的层次上,事情可以得到更好的整合。
猜你喜欢
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 2020-06-19
  • 1970-01-01
  • 2021-06-10
相关资源
最近更新 更多