J'aimerais scinder une très grande chaîne (disons 10 000 caractères) en morceaux de taille N.
Quel serait le meilleur moyen en termes de performances de le faire?
Par exemple: "1234567890"
divisé par 2 deviendrait ["12", "34", "56", "78", "90"]
.
Est-ce que quelque chose comme cela serait possible en utilisant String.prototype.match
et si oui, serait-ce la meilleure façon de le faire en termes de performances?
Vous pouvez faire quelque chose comme ça:
"1234567890".match(/.{1,2}/g);
// Results in:
["12", "34", "56", "78", "90"]
La méthode fonctionnera toujours avec des chaînes dont la taille n'est pas un multiple exact de la taille de bloc:
"123456789".match(/.{1,2}/g);
// Results in:
["12", "34", "56", "78", "9"]
En général, pour toute chaîne dont vous souhaitez extraire au moins les sous-chaînes de taille n, vous feriez:
str.match(/.{1,n}/g); // Replace n with the size of the substring
Si votre chaîne peut contenir des retours à la ligne ou des retours à la ligne, procédez comme suit:
str.match(/(.|[\r\n]){1,n}/g); // Replace n with the size of the substring
En ce qui concerne les performances, j'ai essayé cela avec environ 10 000 caractères et cela a pris un peu plus d'une seconde sous Chrome. YMMV.
Ceci peut également être utilisé dans une fonction réutilisable:
function chunkString(str, length) {
return str.match(new RegExp('.{1,' + length + '}', 'g'));
}
match
, slice
, substr
et substring
match
et slice
pour différentes tailles de morceauxmatch
et slice
avec une petite taille de morceauLigne de fond:
match
est très inefficace, slice
est meilleur, sous Firefox substr
/substring
est encore meilleurmatch
est encore plus inefficace pour les chaînes courtes (même avec des regex en cache - probablement en raison du temps de configuration de l'analyse des regex)match
est encore plus inefficace pour les gros morceaux (probablement en raison de l'impossibilité de "sauter")match
surpasse slice
sur les anciens IE mais perd sur tous les autres systèmesJ'ai créé plusieurs variantes plus rapides que vous pouvez voir sur jsPerf . Mon préféré est celui-ci:
function chunkSubstr(str, size) {
const numChunks = Math.ceil(str.length / size)
const chunks = new Array(numChunks)
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = str.substr(o, size)
}
return chunks
}
C'est la solution la plus rapide et la plus performante:
function chunkString(str, len) {
var _size = Math.ceil(str.length/len),
_ret = new Array(_size),
_offset
;
for (var _i=0; _i<_size; _i++) {
_offset = _i * len;
_ret[_i] = str.substring(_offset, _offset + len);
}
return _ret;
}
Comparez-le aux autres ; Je gagne :)
Surprise! Vous pouvez utiliser split pour scinder.
var parts = "1234567890 ".split(/(.{2})/).filter(O=>O)
Résultats en [ '12', '34', '56', '78', '90', ' ' ]
var str = "123456789";
var chunks = [];
var chunkSize = 2;
while (str) {
if (str.length < chunkSize) {
chunks.Push(str);
break;
}
else {
chunks.Push(str.substr(0, chunkSize));
str = str.substr(chunkSize);
}
}
alert(chunks); // chunks == 12,34,56,78,9
J'ai écrit une fonction étendue, donc la longueur du morceau peut aussi être un tableau de nombres, comme
String.prototype.chunkString = function(len) {
var _ret;
if (this.length < 1) {
return [];
}
if (typeof len === 'number' && len > 0) {
var _size = Math.ceil(this.length / len), _offset = 0;
_ret = new Array(_size);
for (var _i = 0; _i < _size; _i++) {
_ret[_i] = this.substring(_offset, _offset = _offset + len);
}
}
else if (typeof len === 'object' && len.length) {
var n = 0, l = this.length, chunk, that = this;
_ret = [];
do {
len.forEach(function(o) {
chunk = that.substring(n, n + o);
if (chunk !== '') {
_ret.Push(chunk);
n += chunk.length;
}
});
if (n === 0) {
return undefined; // prevent an endless loop when len = [0]
}
} while (n < l);
}
return _ret;
};
Le code
"1234567890123".chunkString([1,3])
retournera:
[ '1', '234', '5', '678', '9', '012', '3' ]
il scinde la grande chaîne en petites chaînes de mots donnés.
function chunkSubstr(str, words) {
var parts = str.split(" ") , values = [] , i = 0 , tmpVar = "";
$.each(parts, function(index, value) {
if(tmpVar.length < words){
tmpVar += " " + value;
}else{
values[i] = tmpVar.replace(/\s+/g, " ");
i++;
tmpVar = value;
}
});
if(values.length < 1 && parts.length > 0){
values[0] = tmpVar;
}
return values;
}
var l = str.length, lc = 0, chunks = [], c = 0, chunkSize = 2;
for (; lc < l; c++) {
chunks[c] = str.slice(lc, lc += chunkSize);
}
Je voudrais utiliser un regex ...
var chunkStr = function(str, chunkLength) {
return str.match(new RegExp('[\\s\\S]{1,' + +chunkLength + '}', 'g'));
}
Utilisation de la méthode slice ():
function returnChunksArray(str, chunkSize) {
var arr = [];
while(str !== '') {
arr.Push(str.slice(0, chunkSize));
str = str.slice(chunkSize);
}
return arr;
}
La même chose peut être faite en utilisant la méthode substring ().
function returnChunksArray(str, chunkSize) {
var arr = [];
while(str !== '') {
arr.Push(str.substring(0, chunkSize));
str = str.substring(chunkSize);
}
return arr;
}
Sous la forme d'une fonction prototype:
String.prototype.lsplit = function(){
return this.match(new RegExp('.{1,'+ ((arguments.length==1)?(isFinite(String(arguments[0]).trim())?arguments[0]:false):1) +'}', 'g'));
}
Voici le code que j'utilise, il utilise String.prototype.slice .
Oui, la réponse est assez longue car elle essaie de respecter les normes en vigueur et contient bien sûr une quantité raisonnable de JSDOC comments. Cependant, une fois minifiés, le code n’est plus que de 828 octets et une fois compressés pour la transmission, ils ne représentent plus que 497 octets.
La méthode que cela ajoute à String.prototype
(en utilisant Object.defineProperty si disponible) est la suivante:
Un certain nombre de tests ont été inclus pour vérifier la fonctionnalité.
Inquiet que la longueur du code affecte la performance? Pas besoin de s'inquiéter, http://jsperf.com/chunk-string/3
Une grande partie du code supplémentaire est là pour vous assurer qu'il répondra de la même manière dans plusieurs environnements javascript.
/*jslint maxlen:80, browser:true, devel:true */
/*
* Properties used by toChunks.
*/
/*property
MAX_SAFE_INTEGER, abs, ceil, configurable, defineProperty, enumerable,
floor, length, max, min, pow, prototype, slice, toChunks, value,
writable
*/
/*
* Properties used in the testing of toChunks implimentation.
*/
/*property
appendChild, createTextNode, floor, fromCharCode, getElementById, length,
log, pow, Push, random, toChunks
*/
(function () {
'use strict';
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
/**
* Defines a new property directly on an object, or modifies an existing
* property on an object, and returns the object.
*
* @private
* @function
* @param {Object} object
* @param {string} property
* @param {Object} descriptor
* @return {Object}
* @see https://goo.gl/CZnEqg
*/
function $defineProperty(object, property, descriptor) {
if (Object.defineProperty) {
Object.defineProperty(object, property, descriptor);
} else {
object[property] = descriptor.value;
}
return object;
}
/**
* Returns true if the operands are strictly equal with no type conversion.
*
* @private
* @function
* @param {*} a
* @param {*} b
* @return {boolean}
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.4
*/
function $strictEqual(a, b) {
return a === b;
}
/**
* Returns true if the operand inputArg is undefined.
*
* @private
* @function
* @param {*} inputArg
* @return {boolean}
*/
function $isUndefined(inputArg) {
return $strictEqual(typeof inputArg, 'undefined');
}
/**
* The abstract operation throws an error if its argument is a value that
* cannot be converted to an Object, otherwise returns the argument.
*
* @private
* @function
* @param {*} inputArg The object to be tested.
* @throws {TypeError} If inputArg is null or undefined.
* @return {*} The inputArg if coercible.
* @see https://goo.gl/5GcmVq
*/
function $requireObjectCoercible(inputArg) {
var errStr;
if (inputArg === null || $isUndefined(inputArg)) {
errStr = 'Cannot convert argument to object: ' + inputArg;
throw new TypeError(errStr);
}
return inputArg;
}
/**
* The abstract operation converts its argument to a value of type string
*
* @private
* @function
* @param {*} inputArg
* @return {string}
* @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tostring
*/
function $toString(inputArg) {
var type,
val;
if (inputArg === null) {
val = 'null';
} else {
type = typeof inputArg;
if (type === 'string') {
val = inputArg;
} else if (type === 'undefined') {
val = type;
} else {
if (type === 'symbol') {
throw new TypeError('Cannot convert symbol to string');
}
val = String(inputArg);
}
}
return val;
}
/**
* Returns a string only if the arguments is coercible otherwise throws an
* error.
*
* @private
* @function
* @param {*} inputArg
* @throws {TypeError} If inputArg is null or undefined.
* @return {string}
*/
function $onlyCoercibleToString(inputArg) {
return $toString($requireObjectCoercible(inputArg));
}
/**
* The function evaluates the passed value and converts it to an integer.
*
* @private
* @function
* @param {*} inputArg The object to be converted to an integer.
* @return {number} If the target value is NaN, null or undefined, 0 is
* returned. If the target value is false, 0 is returned
* and if true, 1 is returned.
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-9.4
*/
function $toInteger(inputArg) {
var number = +inputArg,
val = 0;
if ($strictEqual(number, number)) {
if (!number || number === Infinity || number === -Infinity) {
val = number;
} else {
val = (number > 0 || -1) * Math.floor(Math.abs(number));
}
}
return val;
}
/**
* The abstract operation ToLength converts its argument to an integer
* suitable for use as the length of an array-like object.
*
* @private
* @function
* @param {*} inputArg The object to be converted to a length.
* @return {number} If len <= +0 then +0 else if len is +INFINITY then
* 2^53-1 else min(len, 2^53-1).
* @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
*/
function $toLength(inputArg) {
return Math.min(Math.max($toInteger(inputArg), 0), MAX_SAFE_INTEGER);
}
if (!String.prototype.toChunks) {
/**
* This method chunks a string into an array of strings of a specified
* chunk size.
*
* @function
* @this {string} The string to be chunked.
* @param {Number} chunkSize The size of the chunks that the string will
* be chunked into.
* @returns {Array} Returns an array of the chunked string.
*/
$defineProperty(String.prototype, 'toChunks', {
enumerable: false,
configurable: true,
writable: true,
value: function (chunkSize) {
var str = $onlyCoercibleToString(this),
chunkLength = $toInteger(chunkSize),
chunked = [],
numChunks,
length,
index,
start,
end;
if (chunkLength < 1) {
return chunked;
}
length = $toLength(str.length);
numChunks = Math.ceil(length / chunkLength);
index = 0;
start = 0;
end = chunkLength;
chunked.length = numChunks;
while (index < numChunks) {
chunked[index] = str.slice(start, end);
start = end;
end += chunkLength;
index += 1;
}
return chunked;
}
});
}
}());
/*
* Some tests
*/
(function () {
'use strict';
var pre = document.getElementById('out'),
chunkSizes = [],
maxChunkSize = 512,
testString = '',
maxTestString = 100000,
chunkSize = 0,
index = 1;
while (chunkSize < maxChunkSize) {
chunkSize = Math.pow(2, index);
chunkSizes.Push(chunkSize);
index += 1;
}
index = 0;
while (index < maxTestString) {
testString += String.fromCharCode(Math.floor(Math.random() * 95) + 32);
index += 1;
}
function log(result) {
pre.appendChild(document.createTextNode(result + '\n'));
}
function test() {
var strLength = testString.length,
czLength = chunkSizes.length,
czIndex = 0,
czValue,
result,
numChunks,
pass;
while (czIndex < czLength) {
czValue = chunkSizes[czIndex];
numChunks = Math.ceil(strLength / czValue);
result = testString.toChunks(czValue);
czIndex += 1;
log('chunksize: ' + czValue);
log(' Number of chunks:');
log(' Calculated: ' + numChunks);
log(' Actual:' + result.length);
pass = result.length === numChunks;
log(' First chunk size: ' + result[0].length);
pass = pass && result[0].length === czValue;
log(' Passed: ' + pass);
log('');
}
}
test();
log('');
log('Simple test result');
log('abcdefghijklmnopqrstuvwxyz'.toChunks(3));
}());
<pre id="out"></pre>
const getChunksFromString = (str, chunkSize) => {
var regexChunk = new RegExp(`.{1,${chunkSize}}`, 'g') // '.' represents any character
return str.match(regexChunk)
}
Appelez-le au besoin
console.log(getChunksFromString("Hello world", 3)) // ["Hel", "lo ", "wor", "ld"]
Qu'en est-il de ce petit morceau de code:
function splitME(str, size) {
let subStr = new RegExp('.{1,' + size + '}', 'g');
return str.match(subStr);
};
window.format = function(b, a) {
if (!b || isNaN(+a)) return a;
var a = b.charAt(0) == "-" ? -a : +a,
j = a < 0 ? a = -a : 0,
e = b.match(/[^\d\-\+#]/g),
h = e && e[e.length - 1] || ".",
e = e && e[1] && e[0] || ",",
b = b.split(h),
a = a.toFixed(b[1] && b[1].length),
a = +a + "",
d = b[1] && b[1].lastIndexOf("0"),
c = a.split(".");
if (!c[1] || c[1] && c[1].length <= d) a = (+a).toFixed(d + 1);
d = b[0].split(e);
b[0] = d.join("");
var f = b[0] && b[0].indexOf("0");
if (f > -1)
for (; c[0].length < b[0].length - f;) c[0] = "0" + c[0];
else +c[0] == 0 && (c[0] = "");
a = a.split(".");
a[0] = c[0];
if (c = d[1] && d[d.length -
1].length) {
for (var d = a[0], f = "", k = d.length % c, g = 0, i = d.length; g < i; g++) f += d.charAt(g), !((g - k + 1) % c) && g < i - c && (f += e);
a[0] = f
}
a[1] = b[1] && a[1] ? h + a[1] : "";
return (j ? "-" : "") + a[0] + a[1]
};
var str="1234567890";
var formatstr=format( "##,###.", str);
alert(formatstr);
This will split the string in reverse order with comma separated after 3 char's. If you want you can change the position.