Создайте массив символов из указанного диапазона

Я прочитал код, в котором кто-то сделал это в Ruby:

puts ('A'..'Z').to_a.join(',')

выход:

A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z

Есть ли что-то в Javascript, что позволит сделать это так же просто? если нет, есть ли модуль Node, который допускает нечто подобное?

Ответы

Ответ 1

Javascript не имеет этой функции изначально. Ниже вы найдете несколько примеров того, как это можно решить:

Нормальная функция, любые символы из базовой плоскости (без проверки суррогатных пар)

function range(start,stop) {
  var result=[];
  for (var idx=start.charCodeAt(0),end=stop.charCodeAt(0); idx <=end; ++idx){
    result.push(String.fromCharCode(idx));
  }
  return result;
};

range('A','Z').join();

То же, что и выше, но как функция, добавленная к прототипу массива и, следовательно, доступная для всех массивов:

Array.prototype.add_range = function(start,stop) {
  for (var idx=start.charCodeAt(0),end=stop.charCodeAt(0); idx <=end; ++idx){
    this.push(String.fromCharCode(idx));
  }
  return this;
};

[].add_range('A','Z').join();

Диапазон от предварительно выбранных символов. Быстрее, чем функции выше, и позволяет использовать alphanum_range('A','z') для обозначения A-Z и a-z:

var alphanum_range = (function() {
  var data = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');
  return function (start,stop) {
    start = data.indexOf(start);
    stop = data.indexOf(stop);
    return (!~start || !~stop) ? null : data.slice(start,stop+1);
  };
})();

alphanum_range('A','Z').join();

Или любой символ из диапазона ascii. Используя кешированный массив, он быстрее, чем функции, которые каждый раз строят массив.

var ascii_range = (function() {
  var data = [];
  while (data.length < 128) data.push(String.fromCharCode(data.length));
  return function (start,stop) {
    start = start.charCodeAt(0);
    stop = stop.charCodeAt(0);
    return (start < 0 || start > 127 || stop < 0 || stop > 127) ? null : data.slice(start,stop+1);
  };
})();

ascii_range('A','Z').join();

Ответ 2

var chars = [].concat.apply([], Array(26))
              .map(function(_, i) { return String.fromCharCode(i+65); })
              .join();

Функция .map может быть генератором функций, который может использоваться для разных наборов символов.

function charRange(start) {
    var base = start.charCodeAt(0);
    return function(_, i) { return String.fromCharCode(i + base); };
}

И вы также можете создать "полный" помощник массива.

function fullArray(len) { return [].concat.apply([], Array(len)); }

Затем используйте их так.

var chars = fullArray(26).map(charRange("A"))
                         .join();

Ответ 3

Взгляните на ответ от kannebec по аналогичному вопросу.

Есть ли у JavaScript такой метод, как "range()" для генерации массива на основе предоставленных границ?

Если вы не хотите добавлять собственную функцию, но в одной строке:

var abc = 
(function(){var output = []; for(var i='A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++)
    output.push(String.fromCharCode(i)); return output;})().join(',');

Ответ 4

TL; DR

// ['a', .. , 'z']
Array.apply(null, {length: 26})
    .map(function (x,i) { return String.fromCharCode(97 + i) });

Или даже

function range(first, last) {
    var a = first.charCodeAt(0)
    var b = last.charCodeAt(0) + 1
    return Array.apply(null, {length: Math.abs(b - a)})
      .map(function (x,i) { return String.fromCharCode(Math.min(a, b) + i) });
}
range('K','M') // => ['K','L','M']
range('$','z') // => "$%&'()*+,-./0123456789:;<=>[email protected][\]^_`abcdefghijklmnopqrstuvwxyz"

Я думаю, что это можно выразить яснее функциональным способом: map [0 .. 25] to ['a' .. 'z'].

Мы можем использовать fromCharCode(n) для преобразования числа в строку. Чтобы найти числовое значение, соответствующее символу, нам понадобится обратная функция, toCharCode(s):

var toCharCode = function(s){ return s.charCodeAt(0) } // 'a' => 97, 'b' => 98, ..

Тогда остальное легко:

Array.apply(null, {length: 26})
     .map(function (x,i) { return String.fromCharCode(97 + i) });

Создает массив из 26 undefined 's: [undefined, ... , undefined]. Затем map index i каждого значения до 97 + i == 'a'.charCodeAt(0) + i (для заглавного ввода в 'A' => 65).

В этой первой строке может потребоваться некоторое объяснение. Фактически мы делаем то же, что и Array(1,2,3) == [1,2,3]. Вместо того, чтобы передавать фактический массив в apply, мы передаем что-то такое quacks, как массив (имеет свойство length). Это приводит к вызову Array(undefined, .. , undefined).

См apply а также "общий массив-подобный объект" для более подробной информации.

Ответ 5

Если вы используете ES6, вы можете сгенерировать последовательность, используя Array.from(), передав объект, похожий на массив, для длину диапазона и функцию отображения в качестве второго аргумента для преобразования ключа массива каждого элемента в диапазоне в символ с помощью String.fromCharCode():

Array.from({ length: 26 }, (_, i) => String.fromCharCode('A'.charCodeAt(0) + i));

Вы также можете использовать конструктор Array (примечание: ES6 позволяет конструкторам вызываться либо с вызовом функции, либо с помощью оператора new) для инициализации массива требуемой длины по умолчанию, заполните его с помощью Array.fill(), затем переместите его через:

Array(26).fill().map((_, i) => String.fromCharCode('A'.charCodeAt(0) + i));

То же самое можно сделать с помощью оператора :

[...Array(26)].map((_, i) => String.fromCharCode('A'.charCodeAt(0) + i));

В приведенных выше трех примерах будет возвращен массив с символами от A до Z. Для пользовательских диапазонов вы можете отрегулировать длину и начальный символ.

Для браузеров, которые не поддерживают ES6, вы можете использовать babel- polyfill или core-js polyfill (core-js/fn/array/from).

Если вы ориентируетесь на ES5, я бы рекомендовал решение Array.apply от @wires, которое очень похоже на это.

Наконец, Underscore/Lodash и Ramda имеют функцию range():

_.range('A'.charCodeAt(0), 'Z'.charCodeAt(0) + 1).map(i => String.fromCharCode(i));

Ответ 6

CoffeeScript компилируется в javascript и имеет числовые диапазоны:

(String.fromCharCode(x+64) for x in [1..26]).join(",")

Здесь ссылка на этот script на сайте coffeescript.org. Вы можете увидеть, с каким javascript он компилируется, и запустить его в своем браузере в прямом эфире.

да, вы можете использовать coffeescript для Node.js)

Ответ 7

Возможно, эта функция вам поможет.

function range ( low, high, step ) {    // Create an array containing a range of elements
    // 
    // +   original by: _argos

    var matrix = [];
    var inival, endval, plus;
    var walker = step || 1;
    var chars  = false;

    if ( !isNaN ( low ) && !isNaN ( high ) ) {
        inival = low;
        endval = high;
    } else if ( isNaN ( low ) && isNaN ( high ) ) {
        chars = true;
        inival = low.charCodeAt ( 0 );
        endval = high.charCodeAt ( 0 );
    } else {
        inival = ( isNaN ( low ) ? 0 : low );
        endval = ( isNaN ( high ) ? 0 : high );
    }

    plus = ( ( inival > endval ) ? false : true );
    if ( plus ) {
        while ( inival <= endval ) {
            matrix.push ( ( ( chars ) ? String.fromCharCode ( inival ) : inival ) );
            inival += walker;
        }
    } else {
        while ( inival >= endval ) {
            matrix.push ( ( ( chars ) ? String.fromCharCode ( inival ) : inival ) );
            inival -= walker;
        }
    }

    return matrix;
}

console.log(range('A','Z')) 
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

Это не мое, взятое из: http://javascript.ru/php/range

Ответ 8

Нет, JavaScript не имеет встроенного объекта Range. Вам нужно будет написать функцию для создания абстрактного диапазона, а затем добавить метод to_a для эквивалентности.

Для удовольствия здесь альтернативный способ получить точный вывод без промежуточных строк.

function commaRange(startChar,endChar){
  var c=','.charCodeAt(0);
  for (var a=[],i=startChar.charCodeAt(0),e=endChar.charCodeAt(0);i<=e;++i){
    a.push(i); a.push(c);
  }
  a.pop();
  return String.fromCharCode.apply(String,a);
}

console.log(commaRange('A','J')); // "A,B,C,D,E,F,G,H,I,J"

Для Node.js существует модуль Lazy.

Ответ 9

Немного другой подход

String.fromCharCode(..." ".repeat(26).split("").map((e,i)=>i+'A'.charCodeAt()))

печатает

"ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Ответ 10

function range(r, x) {
    var c1 = r.charCodeAt(0)+1, c2 = r.charCodeAt(3), s = r[0];
    if(c1 && c2)while (c1 <= c2) s += (x || "") + String.fromCharCode(c1++);
    return s;
}

range("A--S", ",");

Ответ 11

var range = [];
for(var i = 65; i < 91; i++)
{
 range.push(String.fromCharCode(i));
}
range = range.join(',');

дает диапазон a-z, но мне также нравится функция.