我有一个服务,需要从一个冗长的原始字符串(比如长度为10,000个字符)中分割出一系列句子。
每个数组中的总字符串" item"需要是完整句子的组合列表(以句点结尾),但该组合列表的总字符数不能超过300个字符。如果尾随句子将数组项的总字符数带到301,则列表必须截断整个句子,并将其用作数组中下一项的开始句...直到原始字符串最终分开。这当然意味着如果一个数组项目缺少最多300个字符就可以了。
我意识到正则表达式的魔力可以做一些非常特殊的事情,但我不确定这是否可行。如果它是......金!如果没有,我甚至会选择能够返回相同结果的Javascript函数。
我的思绪根本无法理解实现这一目标的方法,我对此事的任何帮助表示感谢。感谢。
答案 0 :(得分:2)
您可以将此视为一种分区问题,您希望将数组分区为符合某些条件的最长块。我们将尝试以尽可能“可读”的方式编写它。我们希望能够写下:
// "Partition array of sentences into sub-arrays with combined length < 300."
var sentenceSubArrays = partition(sentences, combinedLengthLessThan300);
这假定您已将文本预分段为sentences
数组。它将返回一个数组数组,我们将其转换为底部组合句子的数组。
我们将combinedLengthLessThan300
定义为
// "Is combined length of strings in array less than 300?"
function combinedLengthLessThan300(array) { return combinedLength(array) <= 300; }
其中combinedLength
只是
// "Compute combined length of array as sum of length of each element."
function combinedLength(array) {
return sum(array.map(function(elt) { return elt.length; }));
}
使用定义为
的sum
函数
function add(a, b) { return a+b; }
function sum(array) { return array.reduce(add); }
如果您愿意,也可以将combinedLength
写为
function combinedLength(array) { return array.join('').length; }
现在,有趣的部分是编写分区例程本身。
// "Partition an array into sub-arrays which satisfy some criterion."
function partition(array, fn) {
array = [array]; // start off with big sub-array
for (var i=0; i < array.length; i++) { // for each sub-array
while (array[i].length > 1 && // if sub-array has 2 or more elts
!fn(array[i])) { // and criteria fails
if (!array[i+1]) array.push([]); // create a new sub-array if necessary
array[i+1].unshift(array[i].pop()); // move offending elt to next sub-array
}
}
return array;
}
这是如何工作的?如评论中所示,基本方法是从一个包含所有原始元素的子数组开始。然后,我们遍历每个子数组,看看它是否满足标准。如果没有,我们将其最后一个元素移动到下一个子数组的前面(必要时创建它)。我并不认为这是非常快。它的性能可能是O(n ^ 2)。此实现优先考虑清晰度和简洁性而非性能。
我们可以使用一个简单的标准测试partition
,每个子数组的长度不能超过2:
>> partition([1,2,3,4,5], function(array) { return array.length <= 2; })
<< [[1, 2], [3, 4], [5]]
最后,将sentenceSubArrays
转换为连续字符串数组:
// "Create array of combined sentences by joining sentences in sub-arrays.
var combinedSentences = sentenceSubArrays.map(function(array) {
return array.join('');
});
希望生成的代码具有可读性,可维护性和可扩展性,并为我们提供了一些实用工具,尤其是partition
,我们可以在其他环境中重复使用。
答案 1 :(得分:1)
如果我了解你,你想将句子合并成小于或等于300个字符的组吗?假设单个句子从未超过300个字符(这可能不是一个好的假设),我认为你可以这样做:
// I didn't know if you have a string of sentences or an array of sentences.
// string of sentences => array of sentences
function sentences(string) {
return string.split(". ");
}
// array of sentences => array of paragraphs less than or equal to 300 characters
function paragraphs(sentences) {
var paragraph = "";
var paragraphs = [];
sentences.forEach(function (sentence) {
if (paragraph.length + sentence.length <= 300) {
paragraph += sentence;
} else {
paragraphs.push(paragraph);
paragraph = sentence;
}
});
if (paragraphs[paragraphs.length - 1] !== paragraph) paragraphs.push(paragraph);
return paragraphs;
}
免责声明:我没有测试此代码。