БлогNot. Javascript: числа в диапазоны и обратно

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 [4557 просмотров]


теги: программирование javascript числа сервис

К этой статье пока нет комментариев, Ваш будет первым