Описание проблемы
Некоторая пустая строка «» появляется при разделении строки с использованием метода разделения JavaScript, особенно при использовании регулярных выражений в качестве разделителей.
Связанные вопросы
Javascript Регулярные выражения создают пустую строковую группу при группировке строк?
В приведенном выше вопросе, вопросник использовал регулярное выражение для разделения строки и сгенерировало несколько пустых строк », а код выглядит следующим образом:
Кода -копия выглядит следующим образом:
'Zhang SDF четыре метода asdf wengf aa33net s'.split (/([/u4e00-/u9fa5] {1})/gi);
// Вывод ["" "," Zhang "," SDF "," Four "," up "," "," Law "," ASDF "," Weng "," "," "," fen "," AA33 "," Net "," S "]
Итак, в чем причина этих пустых строк?
Анализ проблем
После поиска в Google я обнаружил, что не было много связанных результатов. Даже если бы было не так много подробных объяснений. Я грубо сказал, а затем дал ссылку на спецификацию ECMASCRIPT. Кажется, что если вы хотите узнать реальную причину, вы можете только укусить пулю и посмотреть на нормы.
Связанные стандарты
Затем, согласно международной практике, сначала перейдите в стандартное городское здание Ecmascript.
Кода -копия выглядит следующим образом:
String.prototype.split (разделитель, предел)
В этой главе подробно представлены этапы выполнения метода разделения. Если вы заинтересованы, вы можете внимательно прочитать его шаг за шагом. Я объясню только шаги, связанные с созданием пустых строк здесь. Если есть какие -либо неподходящие моменты, можно упомянуть их.
Связанные шаги
Частичные шаги для извлечения:
Наиболее важным шагом во всем процессе является 13 -й цикл, и основные вещи, которые делает этот цикл, заключаются в следующем:
• Определите значения P и Q. Значения P и Q одинаковы в начале каждого цикла (этот шаг находится за пределами цикла);
• Метод вызовов SplitMatch (S, Q, R) для разделения строки;
• Выполнять разные ветви в соответствии с возвращенными результатами, а основными ветвями являются ветви;
• Ветвь делится на 8 небольших шагов, чтобы заполнить возвращенный результат в предопределенный массив A
• В этом 8 небольших шагах цель шага 1 - вернуть подстроение исходной строки, начальная позиция - P (включенная), а конечная позиция - Q (включен). Примечание. На этом этапе будет сгенерирована пустая строка, и я пометил ее как перехватывание строки для удобства цитирования ниже.
• Добавьте подстроение с предыдущего шага к массиву А
• Следующие несколько шагов предназначены для обновления соответствующих переменных и продолжение следующего цикла. (Цель шага 7 - сохранить группировку захвата в регулярном выражении в массив A, что не имеет ничего общего с генерацией пустой строки)
Splitmatch (S, Q, R)
Далее нам нужно понять, что делает метод SplitMatch (S, Q, R). Этот метод упоминается ниже в разделенной спецификации. В основном он выполняет соответствующие операции в соответствии с типом сепаратора:
• Если разделитель имеет тип regexp, вызов внутреннего метода regexp [[Match]], чтобы соответствовать строке. Если матч не удается, верните сбой. В противном случае вернуть результат матча.
• Если разделитель является строкой, выполняется суждение соответствия, возвращается сбой, а результат типа MatchResult успешно возвращается.
Матч
В приведенных выше шагах вводится переменная типа MatchResult. Посмотрев документ, было обнаружено, что переменные этого типа имеют два атрибута Endindex и захваты. Значение эндодекс - это позиция, соответствующая строке плюс 1. Уловы могут быть поняты как массив. Когда разделитель является регулярным выражением, элементы внутри него являются значениями, захваченными группой; Когда разделитель является строкой, это пустой массив.
Следующий
Из приведенных выше шагов мы видим, что разделенная строка генерируется на этапе перехвата строки (за исключением группы регулярных выражений). Его функция состоит в том, чтобы перехватить строку между указанным запуска (включенным) и конечной позицией (включена), так, когда она вернет ""? Существует особый случай, когда значения начальной позиции и конечной позиции равны, что является просто предположением, поскольку спецификация не дает шагов спецификации для перехвата строки.
Мы все пришли сюда, почему бы не сделать шаг вперед?
Итак, я попытался найти какой -то исходный код V8, чтобы увидеть, смогу ли я найти конкретный метод реализации. Я нашел соответствующий код, ссылка на исходный код
Вот некоторые из них:
Кода -копия выглядит следующим образом:
функция StringsPlitjs (сепаратор, предел) {
...
...
// разделитель - это строка
if (! is_regexp (разделитель)) {
var seperator_string = to_string_inline (seperator);
if (limit === 0) return [];
// ECMA-262 говорит, что если сепаратор не определен, результат должен
// быть массивом размера 1, содержащего всю строку.
if (is_undefined (разделитель)) return [субъект];
var seperator_length = separator_string.length;
// сепаратор - это пустая строка, которая непосредственно возвращает массив символов
if (separator_length === 0) return %stringToarray (субъект, предел);
var result = %stringsplit (субъект, separator_string, limit);
результат возврата;
}
if (limit === 0) return [];
// Когда разделитель является регулярным выражением, вызовите StringsPlitonRegexp
return StringsplitonRegexp (субъект, сепаратор, предел, длина);
}
// здесь опущены несколько кодов
Я обнаружил в коде, что при заполнении массива метод %_substring будет вызван для перехвата строки. К сожалению, я не нашел его соответствующего определения. Если есть студенты, которые нашли это, пожалуйста, дайте мне знать. Тем не менее, я обнаружил, что метод StringsUbstring, соответствующий методу подстроки в JavaScript, будет вызовать метод %_substring и вернуть результат. Затем, если 'abc'.substring (1,1) возвращается "", это означает, что метод %_substring вернется "", когда начальная позиция и конечная позиция одинаковы. Вы можете сказать результат, попробовавшись.
Итак, когда произойдет начальная позиция равным конечной позиции (то есть Q === P)? Я следовал вышеуказанным шагам шаг за шагом и наконец нашел:
• Когда исходная строка S соответствует разделителю один раз, сразу после этого, следующая позиция строки S также соответствует разделителю. Например: 'abbbc'.split (' b '),' abbbc'.split (/(b) {1}/)
• Еще один случай - это один или несколько символов в начале строки, соответствующий сепаратору. Например: 'abc'.split (' a '),' abc'.split (/ab/)
• Существует еще один случай, когда одна или несколько строк в конце строки соответствуют разделителю, а соответствующий шаг - шаг 14.
Например: 'abc'.split (' c '),' abc'.split (/bc/)
Кроме того, при использовании регулярных выражений в качестве разделителей не определено может появиться в возвращенном результате.
Например: 'abc'.split (/(d)*/)
Давайте посмотрим на пример в начале. Удовлетворяет ли это вышеупомянутые ситуации?
Не по теме
Это первый раз, когда я так тщательно прочитал стандартные спецификации Ecmascript. Процесс чтения действительно очень болезнен, но после того, как я понимаю, я чувствую себя очень счастливым. Спасибо за этот вопрос и последующий вопрос.
Кстати, когда регулярное выражение используется в качестве сепаратора, глобальный модификатор G будет игнорироваться, что также является дополнительным усилением.