【问题标题】:Split string in array on whitespace before the 10th character在第 10 个字符之前的空白处拆分数组中的字符串
【发布时间】:2020-09-03 14:42:56
【问题描述】:

我想将一个字符串拆分为 10 个字符。但我不想拆分为一个单词。

因此字符串“还有九个字符 - 然后还有更多”将被拆分为 ["Nine", "characters", "to go -", "then some", "more"]
超过 10 个字符的单词可以拆分。

我使用正则表达式最接近的是.{1,10}(?<=\s)
这会将“九个字符-然后更多”拆分为["Nine ", "haracters ", "to go - ", "then some "]
但行为很奇怪。在示例字符串中,它完全跳过了字符“c”。在其他测试字符串中,它只会在单独的数组项中添加“-”,而只有破折号适合它之前的数组项。所以它在空格之后分裂。

我还尝试在空格 (.split(' ')) 上使用 .split(),并使用 .reduce() 或 for 循环将数组项连接到其他最多 10 个字符的数组项中。

for ( i = 0; i < splitArray.length; i++ ) {
  if ( i === 0 ) {
    // add first word in new array. Doesn't take into account yet that word can be longer than 10 characters
    newArray.push( splitArray[i] );
  } else {
    if ( newArray[ newArray.length - 1 ].length + splitArray[i].length + 1 < 10 ) {
      // if next word fits with the word in the new array (taking space into account), add it to it
      newArray[ newArray.length - 1 ] = newArray[ newArray.length - 1 ] + " " + splitArray[i];
    } else if ( newArray[ newArray.length - 1 ].length + splitArray[i].length + 1 >= 10 ) {
      // next word doesn't fit
      // split word and add only part to it and add the rest in separate item in newArray
      const index = 9 - newArray[ newArray.length - 1 ].length
      const prev = splitArray[i].slice( 0, index );
      const next = splitArray[i].slice( index, splitArray[i].length );
      newArray[ newArray.length - 1 ] = newArray[ newArray.length - 1 ] + " " + prev;
      newArray.push( next );
    } else {
      // push new item in newArray
      newArray.push( splitArray[i] );
    }
  }
}

结果:["Nine chara", "cters to g", "o - then s", "ome more"].
没有else if["Nine", "characters", "to go -", "then some", "more"]
没有else if 其他字符串:["Paul van", "den Dool", "-", "Alphabet", "- word"]
这很接近,但“字母”不会与连字符连接,因为它们不适合。我尝试用else if 声明来捕捉它,但这又破坏了我不想破坏的单词,并且与上面的正则表达式的结果相同。

我在这个问题上已经筋疲力尽了,我需要蜂巢思维来解决这个问题。因此,非常感谢您对此提供任何帮助。

上下文
我正在尝试在具有最小字体大小的有限大小框中显示画布上的文本。我的解决方案是在必要时将用户可以输入的字符串分成多行。为此,我需要将字符串拆分为一个数组,对其进行循环并相应地定位文本。

【问题讨论】:

  • 你得到了很多关于算法的答案来进行分割......但请记住,并非所有字母在画布中都有相同的大小,也许你应该测量文本查看measureText@987654321 @你可能会在你真的不需要分裂的地方分裂
  • 确实如此。老实说,还没有想到这一点。但在完整的上下文中,文本将显示在一个正方形中,该正方形将显示在网络摄像头流顶部的画布上。方块会贴在你的额头上。当您移动头部时,正方形的大小会发生变化,尤其是当您前后移动头部时。所以我想我必须先在画布中添加文本来测量它,然后进行所有计算才能正确显示它。这需要用实际上每 50 毫秒发生一次的正方形进行更新。这可能会使这种方法比我想象的要重。
  • 可能会帮助您完成最初的任务:stackoverflow.com/a/54472418/3702797

标签: javascript arrays regex canvas text


【解决方案1】:

使用

console.log(
  "Nine characters to go - then some more"
     .match(/.{1,10}(?=\s|$)/g)
     .map(z => z.trim())
);

使用.match(/.{1,10}(?=\s|$)/g),项目长度为 1 到 10 个字符,(?=\s|$) 将确保匹配空格或字符串结尾。

【讨论】:

  • 您可以使用/(?&lt;!\S).{1,10}(?=\s|$)/g 来避免修剪步骤吗?
  • @Ryszard 这似乎适用于这个字符串,但在其他测试字符串的自己的数组项中添加了连字符。这绝对是对我的改进,但其他答案似乎更接近。我在这里创建了一个包含所有答案的测试用例:jsfiddle.net/35Lso9uv
  • @CarySwoveland 这似乎解决了“连字符在其自己的数组项中”的问题,但如果单词超过 10 个字符,则跳过(未添加)
【解决方案2】:

const string = "Nine characters to go - then some more"
let arr = string.split(" ");
for(let i = 1; i < arr.length; i++) {
  if(arr[i].length >= 10 || arr[i].length + arr[i-1].length >= 10) {
     continue;
  }
  if(arr[i].length < 10 && arr[i].length + arr[i-1].length <= 10) {
    arr[i] = arr[i - 1] + " " + arr[i];
    arr[i-1] = false;
  }

}
arr = arr.filter(string => string)

console.log(arr);

【讨论】:

  • 嗨@Gendy,这对我来说似乎是个赢家。这不会拆分长度超过 10 个字符的单词,但正如其他答案所示,这可能会很麻烦,因为数组中间的某些数组项或开头可能只有一个或几个字符,这看起来很奇怪如果在我的项目中放在单独的行中。
  • 感谢您的评论。要使函数更短,您可以删除此行 if(arr[i].length &gt;= 10 || arr[i].length + arr[i-1].length &gt;= 10) { continue; } 它们用于演示而不是逻辑。
【解决方案3】:

如果需要拆分,使用.split():

const str = 'Nine characters to go - then some more',
      
      result = str.split(/(.{1,10})\s/).filter(Boolean)
      
console.log(result)

【讨论】:

  • 我不知道你可以在正则表达式上拆分!这很酷。我喜欢这个答案,但有点缺点是,如果一个单词超过 10 个字符(比如说 12 个),它会在自己的数组项中添加前两个字母,然后在第二个中添加其余字母。我在这里创建了一个带有所有答案的小测试工具:jsfiddle.net/35Lso9uv
  • @PaulvandenDool :这不正是您原始帖子中的要求('...如果超过10个字符,单词可以拆分')?如果您正在寻求其他一些行为,可以进一步调整上述方法,同时保持整洁。无论如何,接受答案的冗长似乎不值得任务的复杂性;)
  • 这确实是我的要求,但我没有预料到这种行为,即使我喜欢这个解决方案,我也不再分割超过 10 个字符的单词。而这一切也让我意识到这两种结果都不是我最终想要的最佳结果。目前正在考虑为用户提供一个可以在其中绘制/写入的框。它将提供适当的大小限制,允许我放弃任何困难的字符串拆分,并在我已经准备好的地方添加用户自己笔迹的漂亮元素带有字体的手写效果。所以最后,可能没有使用任何这些。
  • @PaulvandenDool :上面一开始提到的上下文可以为您节省时间,因为会建议更多相关选项。我不是在推动我的解决方案,但您应该考虑在 paragraph 中间有一些未拆分的长单词(将几个字符移出)看起来也很丑陋。但是,您是对的,您需要更智能的自动换行方法。
  • 通过这个项目,我边走边学。我认为这是要走的路,但睡个好觉让我不这么认为。我不想发布一些模糊的上下文,就像“给我解决方案!”。但我非常感谢你和我一起思考。如果您有任何基于完整上下文的其他建议,我会全力以赴 :)
【解决方案4】:

我可以使用一个简单的for 循环来解决这个问题:

const str = "Nine characters to go - then some more";

// make an array with each words
const arr = str.trim().split(' ');

// This is the length, how much we want to take the length of the words
const length = 10;
const res = [];

/**
 * Put the first word into the result array
 * because if the word greater or less than
 * the `length` we have to take it.
 */
res.push(arr[0]);

// Result array's current index
let index = 0;

for (let i = 1, l = arr.length; i < l; i++) {
  /**
   * If the length of the concatenation of the
   * last word of the result array
   * and the next word is less than or equal to the length
   * then concat them and put them as the last value
   * of the resulting array.
   */
  if ((res[index] + arr[i]).length <= length) {
    res[index] += ' ' + arr[i];
  } else {
    /**
     * Otherwise push the current word
     * into the resulting array
     * and increase the last index of the
     * resulting array.
     */
    res.push(arr[i]);
    index++;
  }
}

console.log(res);
.as-console-wrapper{min-height: 100%!important; top: 0}

【讨论】:

  • 嗨,萨吉布!这个答案对我有用。它不会拆分超过 10 个字符的单词,但其他答案证明我这可能很麻烦。这个答案与@Gendy 的答案相同,但他的答案稍微不那么冗长(不包括 cmets)。
  • 感谢您的评论。我没有看到其他答案。我试图让解决方案尽可能的干净和小巧。顺便说一句,您的问题对我来说似乎很有趣。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
  • 2014-08-07
  • 2017-06-02
  • 2012-01-08
相关资源
最近更新 更多