WedX - журнал о программировании и компьютерных науках

Есть ли версия JavaScript String.indexOf (), которая позволяет использовать регулярные выражения?

Есть ли в javascript эквивалент String.indexOf (), который принимает регулярное выражение вместо строки для первого первого параметра, но при этом позволяет использовать второй параметр?

Мне нужно сделать что-то вроде

str.indexOf(/[abc]/ , i);

и

str.lastIndexOf(/[abc]/ , i);

Хотя String.search () принимает регулярное выражение в качестве параметра, он не позволяет мне указать второй аргумент!

Изменить:
Это оказалось сложнее, чем я первоначально думал, поэтому я написал небольшую тестовую функцию для проверки всех предоставленных решений ... предполагается, что regexIndexOf и regexLastIndexOf были добавлены к объекту String.

function test (str) {
    var i = str.length +2;
    while (i--) {
        if (str.indexOf('a',i) != str.regexIndexOf(/a/,i)) 
            alert (['failed regexIndexOf ' , str,i , str.indexOf('a',i) , str.regexIndexOf(/a/,i)]) ;
        if (str.lastIndexOf('a',i) != str.regexLastIndexOf(/a/,i) ) 
            alert (['failed regexLastIndexOf ' , str,i,str.lastIndexOf('a',i) , str.regexLastIndexOf(/a/,i)]) ;
    }
}

и я тестирую следующее, чтобы убедиться, что хотя бы для одного символа регулярного выражения результат такой же, как если бы мы использовали indexOf

// Ищем среди xes
test ('xxx');
test ('axx');
test ('xax');
test ('xxa'); < br> test ('axa');
test ('xaa');
test ('aax');
test ('aaa');

07.11.2008

  • | внутри [ ] соответствует буквальному символу |. Вы, наверное, имели в виду [abc]. 08.11.2008
  • да спасибо вы правы, я исправлю но само регулярное выражение не имеет значения ... 08.11.2008
  • Обновил мой ответ Пэт, спасибо за любой отзыв. 08.11.2008
  • Я нашел более простой и эффективный подход - просто использовать string.match (/ [A-Z] /). Если их мало, метод возвращает null, в противном случае вы получаете объект, вы можете выполнить match (/ [A-Z] /). Index, чтобы получить индекс первой заглавной буквы. 26.03.2019

Ответы:


1

Комбинируя несколько уже упомянутых подходов (indexOf, очевидно, довольно прост), я думаю, что это функции, которые помогут:

function regexIndexOf(string, regex, startpos) {
    var indexOf = string.substring(startpos || 0).search(regex);
    return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}

function regexLastIndexOf(string, regex, startpos) {
    regex = (regex.global) ? regex : new RegExp(regex.source, "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : ""));
    if(typeof (startpos) == "undefined") {
        startpos = string.length;
    } else if(startpos < 0) {
        startpos = 0;
    }
    var stringToWorkWith = string.substring(0, startpos + 1);
    var lastIndexOf = -1;
    var nextStop = 0;
    while((result = regex.exec(stringToWorkWith)) != null) {
        lastIndexOf = result.index;
        regex.lastIndex = ++nextStop;
    }
    return lastIndexOf;
}

ОБНОВЛЕНИЕ: отредактировано regexLastIndexOf(), так что теперь похоже, что он имитирует lastIndexOf(). Пожалуйста, дайте мне знать, если он по-прежнему не работает и при каких обстоятельствах.


ОБНОВЛЕНИЕ: Проходит все тесты, найденные в комментариях на этой странице, и мои собственные. Конечно, это не значит, что он пуленепробиваемый. Любая обратная связь приветствуется.

08.11.2008
  • Ваш regexLastIndexOf вернет только индекс последнего неперекрывающегося совпадения. 08.11.2008
  • Извините, я не ОГРОМНЫЙ парень с регулярными выражениями - вы можете привести мне пример, который заставил бы меня потерпеть неудачу? Я ценю возможность узнать больше, но ваш ответ не поможет такому невежеству, как я. :) 08.11.2008
  • Джейсон: Я просто добавил функцию для проверки в вопросе. это не удается (среди других тестов) следующий 'axx'.lastIndexOf (' a ', 2)! =' axx'.regexLastIndexOf (/ a /, 2) 08.11.2008
  • Хорошо, я прошел этот тест и потратил больше времени на поиск соответствующих деталей. 08.11.2008
  • aaaaa.regexLastIndexOf (/ aaa /). Он найдет первые три а, а затем попытается снова сопоставить последние два, что не удастся. aaaaa.lastIndexOf (aaa) находит последние три a. 09.11.2008
  • Ах, попался. Что ж, я на этом закончил - у меня нет времени делать что-либо дальше. :( Это было весело. 09.11.2008
  • Неважно, я сделал еще один удар. :) Больше отзывов приветствуются. 09.11.2008
  • Наконец-то у меня появилось время протестировать предлагаемые решения, и ваше решение оказалось лучше, поэтому я принимаю его на данный момент. 01.11.2009
  • Я думаю, что эффективнее использовать regex.lastIndex = result.index + 1; вместо regex.lastIndex = ++nextStop;. Надеюсь, он перейдет к следующему матчу намного быстрее без потери результата. 30.05.2012
  • @Gedrox Да, я думаю, что он имеет квадратичную временную сложность без вашего предложения, когда он может иметь линейную сложность, если RegExp достаточно короткий. 16.12.2014
  • Как насчет ситуации, когда строка содержит несколько объектов JSON или несколько частей, заполняющих регулярное выражение? 16.04.2015
  • Если вы предпочитаете извлекать его из npm, эти две служебные функции теперь находятся в NPM как: npmjs .com / package / index-of-regex. 26.10.2016

  • 2

    Экземпляры конструктора String имеют метод .search() , который принимает RegExp и возвращает индекс первого совпадения.

    Чтобы начать поиск с определенной позиции (имитируя второй параметр .indexOf()), вы можете slice убрать первые i символов:

    str.slice(i).search(/re/)
    

    Но это получит индекс в более короткой строке (после того, как первая часть была отрезана), поэтому вы захотите затем добавить длину отрезанной части (i) к возвращаемому индексу, если это не было -1. Это даст вам индекс в исходной строке:

    function regexIndexOf(text, re, i) {
        var indexInSuffix = text.slice(i).search(re);
        return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + i;
    }
    
    07.11.2008
  • из вопроса: Хотя String.search () принимает регулярное выражение в качестве параметра, он не позволяет мне указать второй аргумент! 08.11.2008
  • str.substr (i) .search (/ re /) 08.11.2008
  • Отличное решение, но результат немного другой. indexOf вернет число с начала (независимо от смещения), тогда как это вернет позицию из смещения. Итак, для паритета вам понадобится что-то вроде этого: function regexIndexOf(text, offset) { var initial = text.substr(offset).search(/re/); if(initial >= 0) { initial += offset; } return initial; } 11.08.2014

  • 3

    У меня для вас есть короткая версия. У меня это хорошо работает!

    var match      = str.match(/[abc]/gi);
    var firstIndex = str.indexOf(match[0]);
    var lastIndex  = str.lastIndexOf(match[match.length-1]);
    

    И если вам нужна версия прототипа:

    String.prototype.indexOfRegex = function(regex){
      var match = this.match(regex);
      return match ? this.indexOf(match[0]) : -1;
    }
    
    String.prototype.lastIndexOfRegex = function(regex){
      var match = this.match(regex);
      return match ? this.lastIndexOf(match[match.length-1]) : -1;
    }
    

    ИЗМЕНИТЬ: если вы хотите добавить поддержку fromIndex

    String.prototype.indexOfRegex = function(regex, fromIndex){
      var str = fromIndex ? this.substring(fromIndex) : this;
      var match = str.match(regex);
      return match ? str.indexOf(match[0]) + fromIndex : -1;
    }
    
    String.prototype.lastIndexOfRegex = function(regex, fromIndex){
      var str = fromIndex ? this.substring(0, fromIndex) : this;
      var match = str.match(regex);
      return match ? str.lastIndexOf(match[match.length-1]) : -1;
    }
    

    Чтобы использовать это так просто:

    var firstIndex = str.indexOfRegex(/[abc]/gi);
    var lastIndex  = str.lastIndexOfRegex(/[abc]/gi);
    
    29.01.2014
  • Это действительно хороший трюк. Было бы здорово, если бы вы расширили его, чтобы он также принимал параметр startIndex, как обычно indeoxOf и lastIndexOf. 03.04.2015
  • @RobertKoritnik - Я отредактировал свой ответ, чтобы поддержать startIndex (или fromIndex). Надеюсь, поможет! 06.04.2015
  • lastIndexOfRegex также должен добавить к результату значение fromIndex. 20.03.2018
  • Ваш алгоритм развалится по следующему сценарию: "aRomeo Romeo".indexOfRegex(new RegExp("\\bromeo", 'gi')); Результатом будет 1, когда должно быть 7, потому что indexOf будет искать ромео в первый раз, независимо от того, находится он в начале слова или нет. 02.05.2020
  • Отличный трюк. Чтобы справиться с ситуацией, отмеченной CoralK, вы можете заменить оператор return indexOfRegex на: if(match){let list=this.split(regex);match.pop();list.pop();return match.join('').length+list.join('').length+(fromIndex||0);}else return -1; 04.07.2021

  • 4

    Использовать:

    str.search(regex)
    

    См. Документацию здесь.

    12.07.2015
  • @OZZIE: Нет, не совсем. Это в основном ответ Гленна (с ~ 150 голосами за), за исключением того, что он без объяснения вообще не поддерживает начальную позицию, отличную от 0, и был опубликован ... семью годами. 03.06.2018

  • 5

    Вы можете использовать substr.

    str.substr(i).match(/[abc]/);
    
    07.11.2008
  • Из известной книги по JavaScript, опубликованной O'Reilly: substr не стандартизирован ECMAScript и поэтому не рекомендуется. Но мне нравится основная идея того, к чему вы клоните. 08.11.2008
  • Это не проблема. Если вы ДЕЙСТВИТЕЛЬНО обеспокоены этим, используйте вместо этого String.substring () - вам просто нужно делать вычисления немного по-другому. Кроме того, JavaScript не должен на 100% зависеть от своего родительского языка. 08.11.2008
  • Это не обычная проблема - если ваш код работает с реализацией, которая не реализует substr, потому что они хотят придерживаться стандартов ECMAScript, у вас возникнут проблемы. Конечно, заменить его на подстроку не так сложно, но хорошо знать об этом. 08.11.2008
  • В тот момент, когда у вас возникают проблемы, у вас есть очень-очень простые решения. Я думаю, что комментарии разумны, но голосование против было педантичным. 28.03.2013
  • Не могли бы вы отредактировать свой ответ, чтобы предоставить рабочий демонстрационный код? 12.06.2018

  • 6

    На основе ответа BaileyP. Основное отличие состоит в том, что эти методы возвращают -1, если шаблон не может быть сопоставлен.

    Изменить: благодаря ответу Джейсона Бантинга у меня появилась идея. Почему бы не изменить свойство .lastIndex регулярного выражения? Хотя это будет работать только для шаблонов с глобальным флагом (/g).

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

    String.prototype.regexIndexOf = function(re, startPos) {
        startPos = startPos || 0;
    
        if (!re.global) {
            var flags = "g" + (re.multiline?"m":"") + (re.ignoreCase?"i":"");
            re = new RegExp(re.source, flags);
        }
    
        re.lastIndex = startPos;
        var match = re.exec(this);
    
        if (match) return match.index;
        else return -1;
    }
    
    String.prototype.regexLastIndexOf = function(re, startPos) {
        startPos = startPos === undefined ? this.length : startPos;
    
        if (!re.global) {
            var flags = "g" + (re.multiline?"m":"") + (re.ignoreCase?"i":"");
            re = new RegExp(re.source, flags);
        }
    
        var lastSuccess = -1;
        for (var pos = 0; pos <= startPos; pos++) {
            re.lastIndex = pos;
    
            var match = re.exec(this);
            if (!match) break;
    
            pos = match.index;
            if (pos <= startPos) lastSuccess = pos;
        }
    
        return lastSuccess;
    }
    
    07.11.2008
  • На данный момент это кажется наиболее многообещающим (после нескольких исправлений синтаксиса) :-) Только провал нескольких тестов на граничных условиях. Такие вещи, как 'axx'.lastIndexOf (' a ', 0)! =' Axx'.regexLastIndexOf (/ a /, 0) ... Я изучаю его, чтобы узнать, могу ли я исправить эти случаи 08.11.2008

  • 7

    RexExp экземпляры уже имеют свойство lastIndex (если они глобальные) и поэтому я копирую регулярное выражение, немного изменяю его в соответствии с нашими целями, exec вставляю его в строку и смотрю на lastIndex. Это неизбежно будет быстрее, чем зацикливание на струне. (У вас достаточно примеров того, как поместить это в прототип строки, верно?)

    function reIndexOf(reIn, str, startIndex) {
        var re = new RegExp(reIn.source, 'g' + (reIn.ignoreCase ? 'i' : '') + (reIn.multiLine ? 'm' : ''));
        re.lastIndex = startIndex || 0;
        var res = re.exec(str);
        if(!res) return -1;
        return re.lastIndex - res[0].length;
    };
    
    function reLastIndexOf(reIn, str, startIndex) {
        var src = /\$$/.test(reIn.source) && !/\\\$$/.test(reIn.source) ? reIn.source : reIn.source + '(?![\\S\\s]*' + reIn.source + ')';
        var re = new RegExp(src, 'g' + (reIn.ignoreCase ? 'i' : '') + (reIn.multiLine ? 'm' : ''));
        re.lastIndex = startIndex || 0;
        var res = re.exec(str);
        if(!res) return -1;
        return re.lastIndex - res[0].length;
    };
    
    reIndexOf(/[abc]/, "tommy can eat");  // Returns 6
    reIndexOf(/[abc]/, "tommy can eat", 8);  // Returns 11
    reLastIndexOf(/[abc]/, "tommy can eat"); // Returns 11
    

    Вы также можете прототипировать функции в объекте RegExp:

    RegExp.prototype.indexOf = function(str, startIndex) {
        var re = new RegExp(this.source, 'g' + (this.ignoreCase ? 'i' : '') + (this.multiLine ? 'm' : ''));
        re.lastIndex = startIndex || 0;
        var res = re.exec(str);
        if(!res) return -1;
        return re.lastIndex - res[0].length;
    };
    
    RegExp.prototype.lastIndexOf = function(str, startIndex) {
        var src = /\$$/.test(this.source) && !/\\\$$/.test(this.source) ? this.source : this.source + '(?![\\S\\s]*' + this.source + ')';
        var re = new RegExp(src, 'g' + (this.ignoreCase ? 'i' : '') + (this.multiLine ? 'm' : ''));
        re.lastIndex = startIndex || 0;
        var res = re.exec(str);
        if(!res) return -1;
        return re.lastIndex - res[0].length;
    };
    
    
    /[abc]/.indexOf("tommy can eat");  // Returns 6
    /[abc]/.indexOf("tommy can eat", 8);  // Returns 11
    /[abc]/.lastIndexOf("tommy can eat"); // Returns 11
    

    Краткое объяснение того, как я изменяю RegExp: Для indexOf мне просто нужно убедиться, что установлен глобальный флаг. Для lastIndexOf of я использую отрицательный прогноз, чтобы найти последнее вхождение, если RegExp уже не соответствовал в конце строки.

    08.11.2008
  • RexExp опечатка в начале 01.05.2021

  • 8

    Это не изначально, но вы, безусловно, можете добавить эту функцию

    <script type="text/javascript">
    
    String.prototype.regexIndexOf = function( pattern, startIndex )
    {
        startIndex = startIndex || 0;
        var searchResult = this.substr( startIndex ).search( pattern );
        return ( -1 === searchResult ) ? -1 : searchResult + startIndex;
    }
    
    String.prototype.regexLastIndexOf = function( pattern, startIndex )
    {
        startIndex = startIndex === undefined ? this.length : startIndex;
        var searchResult = this.substr( 0, startIndex ).reverse().regexIndexOf( pattern, 0 );
        return ( -1 === searchResult ) ? -1 : this.length - ++searchResult;
    }
    
    String.prototype.reverse = function()
    {
        return this.split('').reverse().join('');
    }
    
    // Indexes 0123456789
    var str = 'caabbccdda';
    
    alert( [
            str.regexIndexOf( /[cd]/, 4 )
        ,   str.regexLastIndexOf( /[cd]/, 4 )
        ,   str.regexIndexOf( /[yz]/, 4 )
        ,   str.regexLastIndexOf( /[yz]/, 4 )
        ,   str.lastIndexOf( 'd', 4 )
        ,   str.regexLastIndexOf( /d/, 4 )
        ,   str.lastIndexOf( 'd' )
        ,   str.regexLastIndexOf( /d/ )
        ]
    );
    
    </script>
    

    Я не тестировал эти методы полностью, но, похоже, пока они работают.

    07.11.2008
  • Обновлено для обработки этих случаев 08.11.2008
  • каждый раз, когда я собираюсь принять этот ответ, я нахожу новый случай! Это дает разные результаты! предупреждение ([str.lastIndexOf (/ [d] /, 4), str.regexLastIndexOf (/ [d] /, 4)]); 08.11.2008
  • ну, конечно, они есть - str.lastIndexOf будет выполнять приведение типов к шаблону, преобразовывая его в строку. Строка / [d] / наверняка не найдена во входных данных, поэтому возвращаемый -1 действительно точен. 08.11.2008
  • Понятно. Прочитав спецификацию String.lastIndexOf () - я просто неправильно понял, как работает этот аргумент. Эта новая версия должна справиться с этим. 08.11.2008
  • Что-то еще не то, но уже поздно ... Попробую получить тест-кейс, а может утром поправлю. Приносим извинения за беспокойство. 08.11.2008
  • Да - я вижу фатальный недостаток в моем подходе к regexLastIndexOf (), который решение MizardX работает лучше. Я посмотрю, смогу ли я сколотить что-нибудь, что инкапсулирует все это 08.11.2008
  • Я просто добавил тестовую функцию к вопросу ... это не проходит этот тест (среди прочего) 'axx'.lastIndexOf (' a ', 1)! =' Axx'.regexLastIndexOf (/ a /, 1) 08.11.2008

  • 9

    После того, как все предложенные решения так или иначе провалили мои тесты (редактировать: некоторые были обновлены для прохождения тестов после того, как я написал это), я нашел реализацию mozilla для Array.indexOf и Array.lastIndexOf

    Я использовал их для реализации моей версии String.prototype.regexIndexOf и String.prototype.regexLastIndexOf следующим образом:

    String.prototype.regexIndexOf = function(elt /*, from*/)
      {
        var arr = this.split('');
        var len = arr.length;
    
        var from = Number(arguments[1]) || 0;
        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
        if (from < 0)
          from += len;
    
        for (; from < len; from++) {
          if (from in arr && elt.exec(arr[from]) ) 
            return from;
        }
        return -1;
    };
    
    String.prototype.regexLastIndexOf = function(elt /*, from*/)
      {
        var arr = this.split('');
        var len = arr.length;
    
        var from = Number(arguments[1]);
        if (isNaN(from)) {
          from = len - 1;
        } else {
          from = (from < 0) ? Math.ceil(from) : Math.floor(from);
          if (from < 0)
            from += len;
          else if (from >= len)
            from = len - 1;
        }
    
        for (; from > -1; from--) {
          if (from in arr && elt.exec(arr[from]) )
            return from;
        }
        return -1;
      };
    

    Кажется, они проходят тестовые функции, которые я указал в вопросе.

    Очевидно, они работают только в том случае, если регулярное выражение соответствует одному символу, но этого достаточно для моей цели, поскольку я буду использовать его для таких вещей, как ([abc], \ s, \ W, \ D)

    Я буду следить за этим вопросом на случай, если кто-то предоставит лучшую / более быструю / более чистую / более общую реализацию, которая работает с любым регулярным выражением.

    08.11.2008
  • Вау, это длинный фрагмент кода. Пожалуйста, проверьте мой обновленный ответ и оставьте отзыв. Спасибо. 08.11.2008
  • Эта реализация нацелена на абсолютную совместимость с lastIndexOf в Firefox и движком SpiderMonkey JavaScript, в том числе в нескольких случаях, которые, возможно, являются крайними случаями. [...] в реальных приложениях вы можете рассчитывать с помощью менее сложного кода, если проигнорируете эти случаи. 09.11.2008
  • Сформируйте страницу Mozilla :-) Я просто взял код и изменил две строчки, оставив все крайние случаи. Поскольку несколько других ответов были обновлены для прохождения тестов, я попробую протестировать их и принять наиболее эффективный. Когда у меня будет время вернуться к этому вопросу. 09.11.2008
  • Я обновил свое решение и ценю любые отзывы или вещи, которые приводят к его сбою. Я внес изменения, чтобы исправить проблему перекрытия, указанную MizardX (надеюсь!) 09.11.2008

  • 10

    Мне также нужна была функция regexIndexOf для массива, поэтому я ее запрограммировал. Однако я сомневаюсь, что он оптимизирован, но я думаю, что он должен работать должным образом.

    Array.prototype.regexIndexOf = function (regex, startpos = 0) {
        len = this.length;
        for(x = startpos; x < len; x++){
            if(typeof this[x] != 'undefined' && (''+this[x]).match(regex)){
                return x;
            }
        }
        return -1;
    }
    
    arr = [];
    arr.push(null);
    arr.push(NaN);
    arr[3] = 7;
    arr.push('asdf');
    arr.push('qwer');
    arr.push(9);
    arr.push('...');
    console.log(arr);
    arr.regexIndexOf(/\d/, 4);
    
    01.09.2012

    11

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

    function regexlast(string,re){
      var tokens=string.split(re);
      return (tokens.length>1)?(string.length-tokens[tokens.length-1].length):null;
    }
    

    Здесь есть несколько серьезных проблем:

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

    Но с другой стороны, это намного меньше кода. Для регулярного выражения постоянной длины, которое не может перекрываться (например, /\s\w/ для поиска границ слов), этого достаточно.

    15.05.2013

    12

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

    function lastIndexOfSearch(string, regex, index) {
      if(index === 0 || index)
         string = string.slice(0, Math.max(0,index));
      var idx;
      var offset = -1;
      while ((idx = string.search(regex)) !== -1) {
        offset += idx + 1;
        string = string.slice(idx + 1);
      }
      return offset;
    }
    

    Для плотных данных я сделал это. Это сложно по сравнению с методом execute, но для плотных данных он в 2-10 раз быстрее, чем любой другой метод, который я пробовал, и примерно в 100 раз быстрее, чем принятое решение. Основные моменты:

    1. Он вызывает exec в переданном регулярном выражении, чтобы убедиться, что есть совпадение, или преждевременно завершить работу. Я делаю это с помощью (? = Аналогичным способом, но в IE проверка с помощью exec выполняется значительно быстрее.
    2. Он создает и кэширует измененное регулярное выражение в формате '(r). (?!.? R)'
    3. Новое регулярное выражение выполняется, и возвращаются результаты либо от этого, либо от первого выполнения;

      function lastIndexOfGroupSimple(string, regex, index) {
          if (index === 0 || index) string = string.slice(0, Math.max(0, index + 1));
          regex.lastIndex = 0;
          var lastRegex, index
          flags = 'g' + (regex.multiline ? 'm' : '') + (regex.ignoreCase ? 'i' : ''),
          key = regex.source + '$' + flags,
          match = regex.exec(string);
          if (!match) return -1;
          if (lastIndexOfGroupSimple.cache === undefined) lastIndexOfGroupSimple.cache = {};
          lastRegex = lastIndexOfGroupSimple.cache[key];
          if (!lastRegex)
              lastIndexOfGroupSimple.cache[key] = lastRegex = new RegExp('.*(' + regex.source + ')(?!.*?' + regex.source + ')', flags);
          index = match.index;
          lastRegex.lastIndex = match.index;
          return (match = lastRegex.exec(string)) ? lastRegex.lastIndex - match[1].length : index;
      };
      

    jsPerf методов

    Я не понимаю цели тестов наверху. Ситуации, требующие регулярного выражения, невозможно сравнивать с вызовом indexOf, что, как мне кажется, является целью создания метода в первую очередь. Чтобы тест прошел, имеет больше смысла использовать «xxx + (?! x)», чем настраивать способ итерации регулярного выражения.

    20.04.2014

    13

    Последний указатель Джейсона Бантинга не работает. Моя не оптимальна, но работает.

    //Jason Bunting's
    String.prototype.regexIndexOf = function(regex, startpos) {
    var indexOf = this.substring(startpos || 0).search(regex);
    return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
    }
    
    String.prototype.regexLastIndexOf = function(regex, startpos) {
    var lastIndex = -1;
    var index = this.regexIndexOf( regex );
    startpos = startpos === undefined ? this.length : startpos;
    
    while ( index >= 0 && index < startpos )
    {
        lastIndex = index;
        index = this.regexIndexOf( regex, index + 1 );
    }
    return lastIndex;
    }
    
    11.06.2015
  • Можете ли вы предоставить тест, который заставит мой провалиться? Если вы обнаружили, что это не работает, предоставьте тестовый пример, зачем просто говорить, что это не работает, и предлагать неоптимальное решение? 10.11.2015
  • Ооо, мальчик. Вы совершенно правы. Я должен был привести пример. К сожалению, я перешел от этого кода несколько месяцев назад и понятия не имею, в чем заключалась ошибка. : - / 12.11.2015
  • ну такова жизнь. :) 18.11.2015

  • 14

    По-прежнему нет собственных методов, выполняющих запрошенную задачу.

    Вот код, который я использую. Он имитирует поведение String.prototype.indexOf и String.prototype.lastIndexOf, но они также принимают RegExp в качестве аргумента поиска в дополнение к строке, представляющей значение для поиска.

    Да, это довольно длинный ответ, поскольку он пытается максимально соответствовать текущим стандартам и, конечно, содержит разумное количество JSDOC комментарии. Однако после минификации размер кода составляет всего 2,27 КБ, а после сжатия для передачи он составляет всего 1023 байта.

    Два метода, которые это добавляет к String.prototype (с использованием Object.defineProperty, если таковые имеются):

    1. searchOf
    2. searchLastOf

    Он проходит все тесты, опубликованные OP, и, кроме того, я довольно тщательно протестировал подпрограммы в своем повседневном использовании и попытался убедиться, что они работают в нескольких средах, но отзывы / проблемы всегда приветствуются.

    /*jslint maxlen:80, browser:true */
    
    /*
     * Properties used by searchOf and searchLastOf implementation.
     */
    
    /*property
        MAX_SAFE_INTEGER, abs, add, apply, call, configurable, defineProperty,
        enumerable, exec, floor, global, hasOwnProperty, ignoreCase, index,
        lastIndex, lastIndexOf, length, max, min, multiline, pow, prototype,
        remove, replace, searchLastOf, searchOf, source, toString, value, writable
    */
    
    /*
     * Properties used in the testing of searchOf and searchLastOf implimentation.
     */
    
    /*property
        appendChild, createTextNode, getElementById, indexOf, lastIndexOf, length,
        searchLastOf, searchOf, unshift
    */
    
    (function () {
        'use strict';
    
        var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1,
            getNativeFlags = new RegExp('\\/([a-z]*)$', 'i'),
            clipDups = new RegExp('([\\s\\S])(?=[\\s\\S]*\\1)', 'g'),
            pToString = Object.prototype.toString,
            pHasOwn = Object.prototype.hasOwnProperty,
            stringTagRegExp;
    
        /**
         * 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
         * @returns {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
         * @returns {boolean}
         * @see https://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
         * @returns {boolean}
         */
        function $isUndefined(inputArg) {
            return $strictEqual(typeof inputArg, 'undefined');
        }
    
        /**
         * Provides a string representation of the supplied object in the form
         * "[object type]", where type is the object type.
         *
         * @private
         * @function
         * @param {*} inputArg The object for which a class string represntation
         *                     is required.
         * @returns {string} A string value of the form "[object type]".
         * @see https://www.ecma-international.org/ecma-262/5.1/#sec-15.2.4.2
         */
        function $toStringTag(inputArg) {
            var val;
            if (inputArg === null) {
                val = '[object Null]';
            } else if ($isUndefined(inputArg)) {
                val = '[object Undefined]';
            } else {
                val = pToString.call(inputArg);
            }
    
            return val;
        }
    
        /**
         * The string tag representation of a RegExp object.
         *
         * @private
         * @type {string}
         */
        stringTagRegExp = $toStringTag(getNativeFlags);
    
        /**
         * Returns true if the operand inputArg is a RegExp.
         *
         * @private
         * @function
         * @param {*} inputArg
         * @returns {boolean}
         */
        function $isRegExp(inputArg) {
            return $toStringTag(inputArg) === stringTagRegExp &&
                    pHasOwn.call(inputArg, 'ignoreCase') &&
                    typeof inputArg.ignoreCase === 'boolean' &&
                    pHasOwn.call(inputArg, 'global') &&
                    typeof inputArg.global === 'boolean' &&
                    pHasOwn.call(inputArg, 'multiline') &&
                    typeof inputArg.multiline === 'boolean' &&
                    pHasOwn.call(inputArg, 'source') &&
                    typeof inputArg.source === 'string';
        }
    
        /**
         * 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.
         * @returns {*} 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
         * @returns {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.
         * @returns {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.
         * @returns {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 https://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;
        }
    
        /**
         * Copies a regex object. Allows adding and removing native flags while
         * copying the regex.
         *
         * @private
         * @function
         * @param {RegExp} regex Regex to copy.
         * @param {Object} [options] Allows specifying native flags to add or
         *                           remove while copying the regex.
         * @returns {RegExp} Copy of the provided regex, possibly with modified
         *                   flags.
         */
        function $copyRegExp(regex, options) {
            var flags,
                opts,
                rx;
    
            if (options !== null && typeof options === 'object') {
                opts = options;
            } else {
                opts = {};
            }
    
            // Get native flags in use
            flags = getNativeFlags.exec($toString(regex))[1];
            flags = $onlyCoercibleToString(flags);
            if (opts.add) {
                flags += opts.add;
                flags = flags.replace(clipDups, '');
            }
    
            if (opts.remove) {
                // Would need to escape `options.remove` if this was public
                rx = new RegExp('[' + opts.remove + ']+', 'g');
                flags = flags.replace(rx, '');
            }
    
            return new RegExp(regex.source, flags);
        }
    
        /**
         * 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.
         * @returns {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);
        }
    
        /**
         * Copies a regex object so that it is suitable for use with searchOf and
         * searchLastOf methods.
         *
         * @private
         * @function
         * @param {RegExp} regex Regex to copy.
         * @returns {RegExp}
         */
        function $toSearchRegExp(regex) {
            return $copyRegExp(regex, {
                add: 'g',
                remove: 'y'
            });
        }
    
        /**
         * Returns true if the operand inputArg is a member of one of the types
         * Undefined, Null, Boolean, Number, Symbol, or String.
         *
         * @private
         * @function
         * @param {*} inputArg
         * @returns {boolean}
         * @see https://goo.gl/W68ywJ
         * @see https://goo.gl/ev7881
         */
        function $isPrimitive(inputArg) {
            var type = typeof inputArg;
    
            return type === 'undefined' ||
                    inputArg === null ||
                    type === 'boolean' ||
                    type === 'string' ||
                    type === 'number' ||
                    type === 'symbol';
        }
    
        /**
         * The abstract operation converts its argument to a value of type Object
         * but fixes some environment bugs.
         *
         * @private
         * @function
         * @param {*} inputArg The argument to be converted to an object.
         * @throws {TypeError} If inputArg is not coercible to an object.
         * @returns {Object} Value of inputArg as type Object.
         * @see https://www.ecma-international.org/ecma-262/5.1/#sec-9.9
         */
        function $toObject(inputArg) {
            var object;
    
            if ($isPrimitive($requireObjectCoercible(inputArg))) {
                object = Object(inputArg);
            } else {
                object = inputArg;
            }
    
            return object;
        }
    
        /**
         * Converts a single argument that is an array-like object or list (eg.
         * arguments, NodeList, DOMTokenList (used by classList), NamedNodeMap
         * (used by attributes property)) into a new Array() and returns it.
         * This is a partial implementation of the ES6 Array.from
         *
         * @private
         * @function
         * @param {Object} arrayLike
         * @returns {Array}
         */
        function $toArray(arrayLike) {
            var object = $toObject(arrayLike),
                length = $toLength(object.length),
                array = [],
                index = 0;
    
            array.length = length;
            while (index < length) {
                array[index] = object[index];
                index += 1;
            }
    
            return array;
        }
    
        if (!String.prototype.searchOf) {
            /**
             * This method returns the index within the calling String object of
             * the first occurrence of the specified value, starting the search at
             * fromIndex. Returns -1 if the value is not found.
             *
             * @function
             * @this {string}
             * @param {RegExp|string} regex A regular expression object or a String.
             *                              Anything else is implicitly converted to
             *                              a String.
             * @param {Number} [fromIndex] The location within the calling string
             *                             to start the search from. It can be any
             *                             integer. The default value is 0. If
             *                             fromIndex < 0 the entire string is
             *                             searched (same as passing 0). If
             *                             fromIndex >= str.length, the method will
             *                             return -1 unless searchValue is an empty
             *                             string in which case str.length is
             *                             returned.
             * @returns {Number} If successful, returns the index of the first
             *                   match of the regular expression inside the
             *                   string. Otherwise, it returns -1.
             */
            $defineProperty(String.prototype, 'searchOf', {
                enumerable: false,
                configurable: true,
                writable: true,
                value: function (regex) {
                    var str = $onlyCoercibleToString(this),
                        args = $toArray(arguments),
                        result = -1,
                        fromIndex,
                        match,
                        rx;
    
                    if (!$isRegExp(regex)) {
                        return String.prototype.indexOf.apply(str, args);
                    }
    
                    if ($toLength(args.length) > 1) {
                        fromIndex = +args[1];
                        if (fromIndex < 0) {
                            fromIndex = 0;
                        }
                    } else {
                        fromIndex = 0;
                    }
    
                    if (fromIndex >= $toLength(str.length)) {
                        return result;
                    }
    
                    rx = $toSearchRegExp(regex);
                    rx.lastIndex = fromIndex;
                    match = rx.exec(str);
                    if (match) {
                        result = +match.index;
                    }
    
                    return result;
                }
            });
        }
    
        if (!String.prototype.searchLastOf) {
            /**
             * This method returns the index within the calling String object of
             * the last occurrence of the specified value, or -1 if not found.
             * The calling string is searched backward, starting at fromIndex.
             *
             * @function
             * @this {string}
             * @param {RegExp|string} regex A regular expression object or a String.
             *                              Anything else is implicitly converted to
             *                              a String.
             * @param {Number} [fromIndex] Optional. The location within the
             *                             calling string to start the search at,
             *                             indexed from left to right. It can be
             *                             any integer. The default value is
             *                             str.length. If it is negative, it is
             *                             treated as 0. If fromIndex > str.length,
             *                             fromIndex is treated as str.length.
             * @returns {Number} If successful, returns the index of the first
             *                   match of the regular expression inside the
             *                   string. Otherwise, it returns -1.
             */
            $defineProperty(String.prototype, 'searchLastOf', {
                enumerable: false,
                configurable: true,
                writable: true,
                value: function (regex) {
                    var str = $onlyCoercibleToString(this),
                        args = $toArray(arguments),
                        result = -1,
                        fromIndex,
                        length,
                        match,
                        pos,
                        rx;
    
                    if (!$isRegExp(regex)) {
                        return String.prototype.lastIndexOf.apply(str, args);
                    }
    
                    length = $toLength(str.length);
                    if (!$strictEqual(args[1], args[1])) {
                        fromIndex = length;
                    } else {
                        if ($toLength(args.length) > 1) {
                            fromIndex = $toInteger(args[1]);
                        } else {
                            fromIndex = length - 1;
                        }
                    }
    
                    if (fromIndex >= 0) {
                        fromIndex = Math.min(fromIndex, length - 1);
                    } else {
                        fromIndex = length - Math.abs(fromIndex);
                    }
    
                    pos = 0;
                    rx = $toSearchRegExp(regex);
                    while (pos <= fromIndex) {
                        rx.lastIndex = pos;
                        match = rx.exec(str);
                        if (!match) {
                            break;
                        }
    
                        pos = +match.index;
                        if (pos <= fromIndex) {
                            result = pos;
                        }
    
                        pos += 1;
                    }
    
                    return result;
                }
            });
        }
    }());
    
    (function () {
        'use strict';
    
        /*
         * testing as follow to make sure that at least for one character regexp,
         * the result is the same as if we used indexOf
         */
    
        var pre = document.getElementById('out');
    
        function log(result) {
            pre.appendChild(document.createTextNode(result + '\n'));
        }
    
        function test(str) {
            var i = str.length + 2,
                r,
                a,
                b;
    
            while (i) {
                a = str.indexOf('a', i);
                b = str.searchOf(/a/, i);
                r = ['Failed', 'searchOf', str, i, a, b];
                if (a === b) {
                    r[0] = 'Passed';
                }
    
                log(r);
                a = str.lastIndexOf('a', i);
                b = str.searchLastOf(/a/, i);
                r = ['Failed', 'searchLastOf', str, i, a, b];
                if (a === b) {
                    r[0] = 'Passed';
                }
    
                log(r);
                i -= 1;
            }
        }
    
        /*
         * Look for the a among the xes
         */
    
        test('xxx');
        test('axx');
        test('xax');
        test('xxa');
        test('axa');
        test('xaa');
        test('aax');
        test('aaa');
    }());
    <pre id="out"></pre>

    26.08.2015

    15

    Если вы ищете очень простой поиск lastIndex с помощью RegExp и не заботитесь о том, имитирует ли он lastIndexOf до последней детали, это может привлечь ваше внимание.

    Я просто переворачиваю строку и вычитаю первый индекс появления из длины - 1. Так получилось, что мой тест прошел, но я думаю, что может возникнуть проблема с производительностью с длинными строками.

    interface String {
      reverse(): string;
      lastIndex(regex: RegExp): number;
    }
    
    String.prototype.reverse = function(this: string) {
      return this.split("")
        .reverse()
        .join("");
    };
    
    String.prototype.lastIndex = function(this: string, regex: RegExp) {
      const exec = regex.exec(this.reverse());
      return exec === null ? -1 : this.length - 1 - exec.index;
    };
    
    04.06.2019

    16

    Я использовал String.prototype.match(regex), который возвращает массив строк всех найденных совпадений заданного regex в строке (подробнее см. Здесь):

    function getLastIndex(text, regex, limit = text.length) {
      const matches = text.match(regex);
    
      // no matches found
      if (!matches) {
        return -1;
      }
    
      // matches found but first index greater than limit
      if (text.indexOf(matches[0] + matches[0].length) > limit) {
        return -1;
      }
    
      // reduce index until smaller than limit
      let i = matches.length - 1;
      let index = text.lastIndexOf(matches[i]);
      while (index > limit && i >= 0) {
        i--;
        index = text.lastIndexOf(matches[i]);
      }
      return index > limit ? -1 : index;
    }
    
    // expect -1 as first index === 14
    console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g, 10));
    
    // expect 29
    console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g));

    16.07.2019

    17
    var mystring = "abc ab a";
    var re  = new RegExp("ab"); // any regex here
    
    if ( re.exec(mystring) != null ){ 
       alert("matches"); // true in this case
    }
    

    Используйте стандартные регулярные выражения:

    var re  = new RegExp("^ab");  // At front
    var re  = new RegExp("ab$");  // At end
    var re  = new RegExp("ab(c|d)");  // abc or abd
    
    31.08.2019

    18

    Для решения, более краткого, чем большинство других опубликованных ответов, вы можете использовать функцию String.prototype.replace, которая будет запускать функцию для каждого обнаруженного шаблона. Например:

    let firstIndex = -1;
    "the 1st numb3r".replace(/\d/,(p,i) => { firstIndex = i; });
    // firstIndex === 4
    

    Это особенно полезно для последнего индексного случая:

    let lastIndex = -1;
    "the l4st numb3r".replace(/\d/g,(p,i) => { lastIndex = i; });
    // lastIndex === 13
    

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

    Наконец, вот более общие функции, которые включают начальный индекс:

    function indexOfRegex(str,regex,start = 0) {
        regex = regex.global ? regex : new RegExp(regex.source,regex.flags + "g");
        let index = -1;
        str.replace(regex,function() {
            const pos = arguments[arguments.length - 2];
            if(index < 0 && pos >= start)
                index = pos;
        });
        return index;
    }
    
    function lastIndexOfRegex(str,regex,start = str.length - 1) {
        regex = regex.global ? regex : new RegExp(regex.source,regex.flags + "g");
        let index = -1;
        str.replace(regex,function() {
            const pos = arguments[arguments.length - 2];
            if(pos <= start)
                index = pos;
        });
        return index;
    }
    

    Эти функции специально избегают разделения строки по начальному индексу, что, на мой взгляд, является рискованным в эпоху Unicode. Они не изменяют прототип общих классов Javascript (хотя вы можете сделать это сами). Они принимают больше флагов RegExp, например u или s, а также любые флаги, которые могут быть добавлены в будущем. И мне легче рассуждать о функциях обратного вызова, чем о циклах for / while.

    29.06.2021

    19

    Что ж, поскольку вы просто хотите сопоставить позицию символа, регулярное выражение, возможно, излишне.

    Я предполагаю, что все, что вам нужно, это вместо «найти первым из этих символов» просто найти первый из этих символов.

    Это, конечно, простой ответ, но он делает то, что задает ваш вопрос, хотя и без части регулярного выражения (потому что вы не пояснили, почему именно это должно быть регулярное выражение)

    function mIndexOf( str , chars, offset )
    {
       var first  = -1; 
       for( var i = 0; i < chars.length;  i++ )
       {
          var p = str.indexOf( chars[i] , offset ); 
          if( p < first || first === -1 )
          {
               first = p;
          }
       }
       return first; 
    }
    String.prototype.mIndexOf = function( chars, offset )
    {
       return mIndexOf( this, chars, offset ); # I'm really averse to monkey patching.  
    };
    mIndexOf( "hello world", ['a','o','w'], 0 );
    >> 4 
    mIndexOf( "hello world", ['a'], 0 );
    >> -1 
    mIndexOf( "hello world", ['a','o','w'], 4 );
    >> 4
    mIndexOf( "hello world", ['a','o','w'], 5 );
    >> 6
    mIndexOf( "hello world", ['a','o','w'], 7 );
    >> -1 
    mIndexOf( "hello world", ['a','o','w','d'], 7 );
    >> 10
    mIndexOf( "hello world", ['a','o','w','d'], 10 );
    >> 10
    mIndexOf( "hello world", ['a','o','w','d'], 11 );
    >> -1
    
    07.11.2008
  • Просто комментарий о патче обезьяны - хотя я знаю о его проблемах - вы думаете, что загрязнение глобального пространства имен лучше? Это не значит, что конфликты символов в ОБЕИХ случаях не могут произойти, и в основном они реорганизуются / исправляются таким же образом в случае возникновения проблемы. 08.11.2008
  • Что ж, мне нужно найти \ s, а в некоторых случаях \ W, и я надеялся, что мне не пришлось перечислять все возможности. 08.11.2008
  • BaileyP: эту проблему можно обойти без загрязнения глобального пространства имен, например: см. JQuery. используйте эту модель. один объект для проекта, внутри него все ваши вещи. Mootools оставил неприятный привкус во рту. 08.11.2008
  • Также следует отметить, что я никогда не кодирую так, как написал там. пример был упрощен по причинам варианта использования. 08.11.2008
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]