2016-05-05 3 views
1

Правильно. В отличие от большинства вопросов, я сам не пытаюсь написать собственное выражение. Я пытаюсь генерировать регулярное выражение (JavaScript приправленный, который будет использоваться в HTML5's pattern attribute).Преобразование массива чисел в подходящее регулярное выражение

Учитывая массив чисел, дайте краткое, быстрое и правильное регулярное выражение, которое будет только соответствует данному входу. Я уже сделал часть работы, а именно те, [0-9]:

var ones = [0, 1, 2, 3, 4, 5, 8, 9], 
 
    onesRegex = ""; 
 
for (var i = 0; i < ones.length; i++) { 
 
    e = ones[i]; 
 
    if (i > 0 && e == ones[i - 1] + 1) { 
 
    if (i != ones[i + 1] - 1) { 
 
     onesRegex += e + "]"; 
 
    } 
 
    } else { 
 
\t if (onesRegex != "") onesRegex += "|"; 
 
    onesRegex += "[" + e + "-"; 
 
    } 
 
} 
 

 
// Returns [0-5]|[8-9] 
 
alert(onesRegex);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Это тогда может быть использовано в <input> (да, JQuery разрешено):

$("input").attr("pattern", onesRegex); 

Проблема, которую я испытываю, заключается в том, что я не уверен, как продолжить. Как вы видите выше, достаточно легко. Тем не менее, все становится все труднее, как только вы начинаете добавлять цифры, потому что вам приходится принимать во внимание так много вещей. Например, вы можете иметь [112, 358, 359, 360, 361], что должно привести к (112|(3(5[8-9]|6[0-1]))), который уже довольно обширен для всего лишь пяти номеров.

Для моего проекта максимальное значение равно 500, поэтому все значения < 1000 должны быть проанализированы.

Я написал совсем немного, но многое предстоит сделать - мне нужно получить логику. Пока моя идея состоит в том, чтобы разделить число в единицах, десятки и сотни, и относиться к ним соответственно. Кроме того, соответствующая функция может опускаться до других функций. Например, разбор номера 512 мог разбить его на 5 и 12, 12 спустится до функции для десятичных знаков и т. Д. Это основная идея, но логика и структура отсутствуют.

Вот что у меня есть, но я также предоставляю a JSFiddle, с которым немного легче работать.

var arr = [0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 105, 106, 107, 256, 257, 258, 259, 260], 
    onesArray = [], 
    tensArray = [], 
    hundredsArray = []; 

// MAIN 
function regexGenerator() { 
    orderSplitter(arr); 
    // Do stuff 
    // Should return finished Regex as a string 
} 

// Split input array in ones (1 digit), tens (2 digits), hundreds (3 digits) 
function orderSplitter(numberArray) { 
    $(numberArray).each(function(index, element) { 
    if (element < 10) { 
     onesArray.push(element); 
    } else if (element < 100 && element > 9) { 
     tensArray.push(element); 
    } else if (element < 1000 && element > 99) { 
     hundredsArray.push(element); 
    } 
    }); 
} 

/* Following functions expect an array as input */ 
function onesToRegex(ones) { 
    var onesRegex = ""; 
    for (var i = 0; i < ones.length; i++) { 
    var e = ones[i]; 
    if (i > 0 && e == ones[i - 1] + 1) { 
     if (i != ones[i + 1] - 1) { 
     onesRegex += e + "]"; 
     } 
    } else { 
     onesRegex += "[" + e + "-"; 
    } 
    } 
    return onesRegex; 
} 

function tensToRegex(tens) { 
    var tensRegex = ""; 
    for (var j = 0; j < tens.length; j++) { 
    var f = tens[j], 
     ten = Math.floor(f/10), 
     one = f - (ten * 10); 

    } 

    return tensRegex; 
} 

function hundredsToRegex(hundreds) { 
    var hundredsRegex = ""; 
    for (var k = 0; k < hundreds.length; k++) { 
    var g = tens[j], 
     hundred = Math.floor(g/100), 
     ten = Math.floor((g - (hundred * 100))/10), 
     one = g - (ten * 10); 

    } 

    return hundredsRegex; 
} 
+0

Я смущен. Если у вас есть массив чисел, вы хотите, чтобы регулярное выражение соответствовало всем # или одному числу или что? – IMTheNachoMan

+0

@IMTheNachoMan Регулярное выражение, которое может соответствовать всем числам в этом массиве. –

+3

Вы можете просто создать шаблон типа '(100 | 200 | 212 | 213 | 214 | 357)' и т. Д. Для каждого номера, правильно? Забудьте о причудливом шаблоне и используйте только определенные значения? –

ответ

0

Предложение с деревом.

В основном это состоит из двух частей

  1. построить дерево с объектом, где длиной смычковых чисел являются первым ключом, а остальные свойства с одной цифрой и объектом.

  2. создайте строку регулярного выражения с итерированием по первому ключу (длина) и запустите iter с содержимым свойства и уменьшенной длиной/глубиной следующего объекта.

function getRegex(array) { 
 
    function group(array) { // take array [0,1,3,4,5,6,8] return string '013-68' 
 
     return array.reduce(function (r, a, i, aa) { 
 
      if (!i || aa[i - 1] + 1 !== a) { 
 
       return r.concat([[a]]); 
 
      } 
 
      r[r.length - 1][1] = a; 
 
      return r; 
 
     }, []).map(function (a) { 
 
      return a.join(a[0] + 1 === a[1] ? '' : '-'); 
 
     }).join(''); 
 
    } 
 

 
    function iter(o, l) { // iterate an object 
 
     // get all keys form the object as sorted numbers 
 
     var keys = Object.keys(o).map(Number).sort(function (a, b) { return a - b; }); 
 

 
     if (keys.length === 1) { // if just one key return the key and get the next level 
 
      return keys[0] + iter(o[keys[0]], l - 1); 
 
     } 
 
     if (keys.length > 1) { // if more than one key 
 
      // test the level 
 
      // if next level 
 
      // return parenthesis with all keys and their next levels separated with | 
 
      // if no level 
 
      // return grouped keys with brackets around 
 
      return l ? 
 
       '(' + keys.map(function (k) { return k + iter(o[k], l - 1); }).join('|') + ')' : 
 
       '[' + group(keys) + ']'; 
 
     } 
 
     return ''; 
 
    } 
 

 
    var tree = {}; 
 
    array.forEach(function (a) { 
 
     var o, s = a.toString(); 
 
     tree[s.length] = tree[s.length] || {}; 
 
     o = tree[s.length]; 
 
     s.split('').forEach(function (b) { 
 
      o[b] = o[b] || {}; 
 
      o = o[b]; 
 
     }); 
 
    }); 
 

 
    return '(' + Object.keys(tree).map(function (k) { return iter(tree[k], +k - 1); }).join('|') + ')'; 
 
} 
 

 
document.write('<pre>' + getRegex([0, 1, 2, 3, 4, 5, 8, 9]) + '</pre>'); 
 
document.write('<pre>' + getRegex([100, 200, 212, 213, 214, 357]) + '</pre>'); 
 
document.write('<pre>' + getRegex([112, 358, 359, 360, 361]) + '</pre>'); 
 
document.write('<pre>' + getRegex([0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 105, 106, 107, 256, 257, 258, 259, 260]) + '</pre>');

+0

Не могли бы вы представить это с некоторыми комментариями (возможно, inline) о том, что на самом деле происходит? Просто отбросить кусок кода для меня не очень учебный. Я написал свой собственный ответ, но меня интересует ваше понимание. –

1

В качестве альтернативного подхода, рассмотреть вопрос об использовании HTML5 <datalist>. Это также может быть сгенерировано в JavaScript.

var arr = [.......]; 

var datalist = document.createElement('datalist'); 
arr.forEach(function(num) { 
    var option = document.createElement('option'); 
    option.value = num; 
    datalist.appendChild(option); 
}); 
datalist.id = "numberlist"; 
document.body.appendChild(datalist); 

// apply to input 
someInputElement.setAttribute("list","numberlist"); 

Вот демо для вас: https://jsfiddle.net/960sjuhc/

+0

Я не думаю, что это удобный подход, когда у вас может быть до 500 значений. –

+0

Это более удобный для пользователя, чем потенциально 500 номеров, и никаких признаков того, что они собой представляют) –

+0

Я не понимаю, что вы подразумеваете под этим. –

-1

Как было отмечено in the comments, я должен был иметь некоторую забаву с ним - и я последовал вашему совету и здесь мы! Мое решение, вероятно, не так эффективно, как ответ Нины Шольц (не тестировался, но этот ответ выглядит просто подробнее ... подробный), но он лучше читается, на мой взгляд, и было очень весело сделать - и совсем не так, как как я думал, когда я обнял его.

Это на JSFiddle. А также здесь как фрагмент. Я сделал все возможное, комментируя некоторые более сложные части, но большинство из них должно быть довольно простым, хотя в ретроспективе я мог бы выбрать несколько лучших имен переменных. Комментарии приветствуются!

var arr = [0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 105, 106, 107, 256, 257, 258, 259, 260], 
 
    onesArray = [], 
 
    tensArray = [], 
 
    tensMultiArray = {}, 
 
    hundredsArray = [], 
 
    hundredsMultiArray = {}; 
 

 
// MAIN 
 
function regexGenerator(arr) { 
 
    orderSplitter(arr); 
 

 
    var onesRegexString = onesToRegex(onesArray); 
 
    var tensRegexString = tensToRegex(tensArray); 
 
    var hundredsRegexString = hundredsToRegex(hundredsArray); 
 

 
    // Don't forget start/end points ^$ 
 
    var regex = "(^(" + onesRegexString + ")$)|(^(" + tensRegexString + ")$)|(^(" + hundredsRegexString + ")$)"; 
 

 
    $(".result code").text(regex); 
 
} 
 

 
regexGenerator(arr); 
 

 
// Split input array in ones (1 digit), tens (2 digits), hundreds (3 digits) 
 
// Can be extended to include others 
 
function orderSplitter(numberArray) { 
 
    $(numberArray).each(function(index, element) { 
 
    if (element < 10) { 
 
     onesArray.push(element); 
 
    } else if (element < 100 && element > 9) { 
 
     tensArray.push(element); 
 
    } else if (element < 1000 && element > 99) { 
 
     hundredsArray.push(element); 
 
    } 
 
    }); 
 
} 
 

 
/* Following functions expect an array as input */ 
 
function onesToRegex(ones) { 
 
    var onesRegex = ""; 
 
    for (var i = 0; i < ones.length; i++) { 
 
    var e = ones[i]; 
 
    // If this element is not the first element, and it is equal to 
 
    // the previous number + 1 
 
    if (i > 0 && e == (ones[i - 1] + 1)) { 
 
     // If this element is NOT equal to the next element - 1 
 
     // Will also return true if next item does not exist 
 
     if (e != (ones[i + 1] - 1)) { 
 
     onesRegex += e + "]"; 
 
     } 
 
    } 
 
    // If this item is a (new) first item in a list 
 
    else { 
 
     if (onesRegex != "") onesRegex += "|"; 
 
     onesRegex += "[" + e + "-"; 
 
    } 
 
    } 
 
    return onesRegex; 
 
} 
 

 
function tensToRegex(tens) { 
 
    var tensRegex = ""; 
 

 
    // Loop the array and break the number down in digits 
 
    // E.g. 13 -> ten = 1; one = 3 
 
    $(tens).each(function(index, element) { 
 
    var ten = Math.floor(element/10), 
 
     one = element - (ten * 10); 
 

 
    // Push items to associative arrays (objects) 
 
    if (!(ten in tensMultiArray)) { 
 
     tensMultiArray[ten] = [one]; 
 
    } else { 
 
     tensMultiArray[ten].push(one); 
 
    } 
 
    }); 
 

 
    var i = 0; 
 
    for (var ten in tensMultiArray) { 
 
    if (tensMultiArray.hasOwnProperty(ten)) { 
 
     // Each iteration is a new number, meaning it is an *alternative* 
 
     // Hence the pipe 
 
     if (i > 0) tensRegex += "|"; 
 
     tensRegex += ten; 
 

 
     // The `one` digits belonging to ten (e.g. 1 and 2 for 11 and 12) is an array 
 
     // Therefore we can send it down to onesToRegex to be processed 
 
     if (tensMultiArray[ten].length > 1) { 
 
     tensRegex += "(" + onesToRegex(tensMultiArray[ten]) + ")"; 
 
     } else { 
 
     tensRegex += tensMultiArray[ten][0]; 
 
     } 
 

 
     i++; 
 
    } 
 
    } 
 
    return tensRegex; 
 
} 
 

 
function hundredsToRegex(hundreds) { 
 
    var hundredsRegex = ""; 
 
    // Loop the array and break the number down in hundreds and rest 
 
    // E.g. 128 -> hundred = 1; rest = 28 
 
    $(hundreds).each(function(index, element) { 
 
    var hundred = Math.floor(element/100), 
 
     rest = element - (hundred * 100); 
 

 
    // Push items to associative arrays (objects) 
 
    if (!(hundred in hundredsMultiArray)) { 
 
     hundredsMultiArray[hundred] = [rest]; 
 
    } else { 
 
     hundredsMultiArray[hundred].push(rest); 
 
    } 
 
    }); 
 

 
    var i = 0; 
 
    for (var hundred in hundredsMultiArray) { 
 
    if (hundredsMultiArray.hasOwnProperty(hundred)) { 
 
     // Each iteration is a new number, meaning it is an *alternative* 
 
     // Hence the pipe 
 
     if (i > 0) hundredsRegex += "|"; 
 
     hundredsRegex += hundred; 
 

 
     // The `rest` digits belonging to hundred (e.g. 28 and 29 for 128 and 129) 
 
     // is an array. Therefore we can send it down to tensToRegex to be processed 
 
     // In turn, tensToRegex will also send its ones through to onesToRegex 
 
     if (hundredsMultiArray[hundred].length > 1) { 
 
     hundredsRegex += "(" + tensToRegex(hundredsMultiArray[hundred]) + ")"; 
 
     } else { 
 
     hundredsRegex += hundredsMultiArray[hundred][0]; 
 
     } 
 

 
     i++; 
 
    } 
 
    } 
 
    return hundredsRegex; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<h1> 
 
Generate Regular Expression based on an input array 
 
</h1> 
 

 
<p> 
 
    In this example the input is <code>[0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 105, 106, 107, 256, 257, 258, 259, 260]</code>. The result is: 
 
</p> 
 
<p class="result"><code></code></p>

Смежные вопросы