Javascript: числа в диапазоны и обратно
Скрипт понадобился мне для извлечения из текста информации о целых числах и диапазонах чисел, записанных в этом тексте (не знаю, как перевести на русский простое "range expansion").
В общем, 1-3
должно превратиться в 1,2,3
, а -5--2,-4-0
в -5,-4,-3,-2,-1,0
, если так понятней (интервалы объединятся, повторяющиеся числа удалятся).
Обратная задача также имеет смысл - например, из числового ряда 1,12,9,8,7 12
мы можем получить
"упакованную" запись 1,7-9,12
- здесь также удалятся дубли, числа отсортируются, а любые три и более натуральных числа, идущие подряд, запишутся в виде диапазона число1-число2
.
Вот небольшой сервис на Javascript, решающий задачу.
Из ввода берутся только целые числа, например, 1.5
или 1,5
превратятся в 1
и 5
.
Кнопку "Распаковать" можно применять ещё и для фильтрации строки от повторяющихся числовых значений.
Код в том виде, что здесь приведён, не является обратимым, то есть упаковка строки, а затем её распаковка не обязана приводить к исходной строке. Это происходит потому, что разрешены любые разделители, а дефис может играть роль как знака перед целым числом, так и разделителя в диапазоне число1-число2
.
Например, из строки
-6,-3 - -1
при её распаковке получатся
диапазон (-6)-(3)
и значение (-1)
, что приведёт к ряду
-6,-5,-4,-3,-2,-1,0,1,2,3
, упаковка же этого ряда даст диапазон
-6-3
Если нужно, диапазоны при распаковке "переворачиваются", то есть,
диапазон 18-11
даст ряд 11,12,13,14,15,16,17,18
, а 2-2
даст значение 2
.
В коде любопытно, как сортировать и фильтровать массивы на Javascript, основные действия закомментированы.
Вот сервис в работе и исходник на момент написания, возможно, он не совсем точен, но мне для моей задачи хватило.
<form name="rangeNumbersForm"> <p>Введите или вставьте числа: <input type="text" name="numbersText" id="numbersText" size="40" maxlength="1000"> <input type="button" value="Упаковать" onclick="doPackNumbers();"> <input type="button" value="Распаковать" onclick="doUnPackNumbers();"> <input type="button" value="Очистить" onclick="doClearNumbers();"> </p> <p>Результат: <input type="text" name="numbersResult" id="numbersResult" size="100" readonly> </p> </form> <script type="text/javascript"> function trim (p) { return p.replace (/\s+/g, ' ').replace(/(^\s*)|(\s*)$/g, ''); } function doPackNumbers () { var str = trim(document.rangeNumbersForm.numbersText.value.replace (/[^-0-9]/g,' ')); //фильтрация строки от всего, кроме цифр и дефисов str = str.replace(/(-?[0-9]+)/g,' $1 '); //добавить пробелы для чисел str = str.replace(/\-{2,}/g,''); //убрать строки из 2 и более дефисов var list = trim(str).split(' '); //получение и сортировка массива list = list.sort (function (a,b) { return a - b; }); //так сортируют числа в JS! list = list.filter (function (item, pos) { return list.indexOf(item) == pos; }); //удаление одинаковых элементов var len = list.length; var out = []; var i, j; var isNull = 0; for (i = 0; i < len; i++) { //упаковка в диапазоны if (Number(list[i])==0) isNull++; if (!isNaN(list[i]) && isNull<2) { //чтобы не было +0 -0 и т.п. яваскриптовых заморочек out.push (Number(list[i])); for (j = i + 1; j<len; j++) { if (Number(list[j-1])+1 != Number(list[j])) break; } j--; if (i == j) { //одно число out.push(','); } else if (i + 1 == j) { //два числа out.push (',', Number(list[j]), ','); i++; } else { //диапазон out.push ('-', Number(list[j]), ','); i += (j-i); } } } out.pop(); //убрать лишнюю запятую в конце document.rangeNumbersForm.numbersResult.value = out.join(''); document.rangeNumbersForm.numbersResult.select(); } function doUnPackNumbers () { var str = trim(document.rangeNumbersForm.numbersText.value.replace (/[^-0-9]/g,' ')); //фильтрация строки от всего, кроме цифр и дефисов str = str.replace(/(-?[0-9]+)(\s*\-\s*)(-?[0-9]+)/g,'$1\-$3'); //извлечение диапазонов, для которых могут быть лишние разделители str = str.replace(/\-{3,}/g,'\-'); //убрать строки из 3 и более дефисов var list = []; var arr = str.split(' '); var len = arr.length; for (var i=0; i<len; i++) { list = list.concat (expandTerm(arr[i])); } list = list.sort (function (a,b) { return a - b; }); list = list.filter (function (item, pos) { return list.indexOf(item) == pos; }); document.rangeNumbersForm.numbersResult.value = list; document.rangeNumbersForm.numbersResult.select(); function expandTerm (term) { var factors = getFactors(term); if (factors.last === undefined) return [Number(factors.first)]; var range = []; for (var n = factors.first; n <= factors.last; n++) range.push(n); return range; } function getFactors (term) { var matches = term.match(/(-?[0-9]+)-(-?[0-9]+)/); if (!matches) return { first: parseInt(term) }; return { first: Math.min(parseInt(matches[1]),parseInt(matches[2])), last: Math.max(parseInt(matches[1]),parseInt(matches[2])) }; } } function doClearNumbers() { document.rangeNumbersForm.numbersText.value = ''; document.rangeNumbersForm.numbersResult.value = ''; } </script> <noscript><p>Нужен включённый Javascript для работы приложения</p></noscript>
В тему:
если от двух отнять два, всё равно останутся два. Ну, может, два других
13.12.2017, 17:14 [4703 просмотра]