如何将一个句子字符串分成两半,形成包含两个字符串的数组,使得每个字符串的长度尽可能相似?

5

我在这里有一个有趣的问题。我有一些JavaScript字符串,如下:

var a = "A few sentences. For tests. The point of these sentences is to be used as examples.";
var b = "A couple more sentences. These ones are shorter.";
var c = "Blah. Foo. Bar. Baz. Test. Test 2. Test C.";
var d = "Test sentence.";

我希望扩展 string 原型,使其具有将每个字符串拆分为两个字符串的方法,每个字符串中的字符数量尽可能相似,同时保持整个句子不被拆开。
我需要的结果是:
a.halve() // ["A few sentences. For tests.", "The point of these sentences is to be used as examples."]
b.halve() // ["A couple more sentences.", "These ones are shorter."]
c.halve() // ["Blah. Foo. Bar. Baz.", "Test. Test 2. Test C."]
d.halve() // ["Test sentence.", ""]

如果我执行 a.length / 2,则可以获得两个字符串的理想目标长度... 我只是在尝试正确顺序下进行 splitjoin


split() 是用来按照分隔符字符进行分割的,而不是位置。请使用 substr() - Barmar
似乎你只能在句子的结尾处进行分割,但问题中并没有说明。 - Barmar
你是否也需要允许?!作为句子结尾?引用句号如何处理,例如他说:“救命啊!”我说:“我来了。” - Barmar
好问题。在我使用的上下文中,只会有句号。 - xd1936
有人可以在这里尝试基于正则表达式的解决方案吗? - Tim Biegeleisen
显示剩余6条评论
5个回答

2

首先将所有内容拆分为句子。然后找到最佳位置进行合并。

var a = "A few sentences. For tests. The point of these sentences is to be used as examples.";
var b = "A couple more sentences. These ones are shorter.";
var c = "Blah. Foo. Bar. Baz. Test. Test 2. Test C.";
var d = "Test sentence.";

String.prototype.halve = function() {
  const ideaLength = this.length / 2;
  const sentences = this.split('.').map(it => it.trim()).filter(it => it != '');
  let current = sentences[0].length + 1;
  let min = Math.abs(current - ideaLength);
  let minPosition = 0;

  for (let i = 1; i < sentences.length; i++) {
    current = current + 2 + sentences[i].length;
    const different = Math.abs(ideaLength - current);
    
    if (different < min) {
      min = different;
      minPosition = i;
    }
  }
  
  const first = sentences.slice(0, minPosition + 1).join('. ') + ".";
  const second = sentences.slice(minPosition + 1).join('. ') + ".";
  
  return [first, second === "." ? "" : second];
}

console.log(a.halve());
console.log(b.halve());
console.log(c.halve());
console.log(d.halve());


绝对完美。我自己的实现才完成一半,远不如这个优雅。非常感谢! - xd1936

2
一个快速的解决方案 :)
Reflect.set(String.prototype, 'halve', function(){
  let mid = Math.floor(this.length/2)
  let i = mid - 1, j = mid, sep = mid
  while(j<this.length) {
    if(this[i]==='.') { sep = i + 1; break }
    if(this[j]==='.') { sep = j + 1; break }
    i--
    j++
  }
  return [this.slice(0,sep), this.slice(sep)]
})

var a = "A few sentences. For tests. The point of these sentences is to be used as examples.";
var b = "A couple more sentences. These ones are shorter.";
var c = "Blah. Foo. Bar. Baz. Test. Test 2. Test C.";
var d = "Test sentence.";

console.log(a.halve()) // ["A few sentences. For tests.", "The point of these sentences is to be used as examples."]
console.log(b.halve()) // ["A couple more sentences.", "These ones are shorter."]
console.log(c.halve()) // ["Blah. Foo. Bar. Baz.", "Test. Test 2. Test C."]
console.log(d.halve()) // ["Test sentence.", ""]

1
非常高效、简洁、聪明。此外,我从未听说过Javascript的Reflect对象!所以也谢谢你带给我的这个信息! - xd1936

1
这可以通过使用 indexOflastIndexOf 找到中间位置来解决:

var a = "A few sentences. For tests. The point of these sentences is to be used as examples.";
var b = "A couple more sentences. These ones are shorter.";
var c = "Blah. Foo. Bar. Baz. Test. Test 2. Test C.";
var d = "Test sentence.";
var e = "A. B. C. D. E. F. G. H. The point of these sentences is to be used as examples."
var f = "The point of these sentences is to be used as examples. A. B. C. D. E. F. G. H."

const half = str => {
  let middle = Math.floor(str.length / 2)
  let nextDot = str.lastIndexOf('.', middle)
  nextDot = nextDot <= 0 ? str.indexOf('.', middle)+1 : nextDot+1
  return [str.substr(0, nextDot), str.substr(nextDot, str.length).trim()]
}

console.log(half(a))
console.log(half(b))
console.log(half(c))
console.log(half(d))
console.log(half(e))
console.log(half(f))

这个想法是使用lastIndexOfindexOf的组合来确定需要向哪个方向移动以达到中间位置。一旦获得了中间位置,就可以使用substr来获取相应的部分。

1
一种易于跟随和有趣的方法!但是这不会根据字符串的字符长度将其分成两半。它非常适用于根据句子数量进行精确拆分,但是如果我有var e = "A. B. C. D. E. F. G. H. 这些句子的重点是作为示例使用。", 它将返回"A. B. C. D. E""F. G. H. 这些句子的重点是作为示例使用。", 而不是"A. B. C. D. E. F. G. H.""这些句子的重点是作为示例使用。". 干杯 :) - xd1936
更新了更简单的实现方式。干杯! - Akrion
这很简单而且非常棒。做得好。因为它从字符串的中间开始,只向一个方向搜索,所以 var e = "The point of these sentences is to be used as examples. A. B. C. D. E. F. G. H." 就会出问题 ;) - xd1936
放心,当lastIndexOf找不到任何内容时,您只需使用indexOf。已更新 :)。 - Akrion

0

以下代码也可以完成任务。它将根据“ ”分割句子并将其拆分为数组。使用新数组,您可以使用Math.floor()获取数组的中间位置并向下取整。然后一些条件将对其进行排序。

var a = "A few sentences. For tests. The point of these sentences is to be used as examples.";
var b = "A couple more sentences. These ones are shorter.";
var c = "Blah. Foo. Bar. Baz. Test. Test 2. Test C.";
var d = "Test sentence.";

function splitString(str){
    var workSplit = str.split(" ");
    var midPoint = Math.floor(workSplit.length / 2);
    var result = [[],[]];
    for(var char in workSplit){
        if(char < midPoint){
            result[0].push(workSplit[char])
        } else {
            result[1].push(workSplit[char]);
        }
    }
    return [result[0].join(" "), result[1].join(" ")]
}

console.log(splitString(a));
console.log(splitString(b));
console.log(splitString(c));
console.log(splitString(d));

0

首先,使用此答案查找您字符串中所有的 "." 发生位置。

然后,找到距离您字符串中心最近的 "." 并在那里分割它(例如,使用此答案:在给定索引处将字符串拆分为两个并返回两个部分

一些代码:

function splitValue(value, index) {
  return [value.substring(0, index), value.substring(index)];
}

function splitStringInTwo(str) {
  const half = Math.trunc(str.length / 2);
  let slicePoint = {position: -1, distance: 9999};

  if (str.indexOf('.')  === -1) {
    return splitValue(str, str.length / 2);
  }

  for (let i = 1; i > 0; i =  str.indexOf('.', i) + 1) {
    if (Math.abs(i - half) < slicePoint.distance) {
      slicePoint = {position: i, distance: Math.abs(i - half)}; // Distance is shrinking, save it.
    } else {
      return splitValue(str, slicePoint.position); // Distance it growing. Stop.
    }
  }


}

const myString = "Here is a first string. My second, though, is larger by a fair amount of characters. I don't want it to be split.";

console.log(splitStringInTwo(myString));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接