Descrição do problema
Alguma string vazia "" aparece ao dividir uma string usando o método dividido do JavaScript, especialmente ao usar expressões regulares como delimitadores.
Perguntas relacionadas
Expressões regulares JavaScript produzem grupo de cordas vazias ao agrupar seqüências de strings?
Na pergunta acima, o questionador usou a expressão regular para dividir a corda e gerar várias strings vazias "" e o código é o seguinte:
A cópia do código é a seguinte:
'Zhang sdf quatro métodos asdf wengf aa33net s'.split (/([/u4e00-/u9fa5] {1})/gi);
// output ["", "Zhang", "SDF", "Four", "Up", "", "Law", "Asdf", "Weng", "", ""
Então, qual é a razão para essas cordas vazias?
Análise de problemas
Depois de pesquisar no Google, descobri que não havia muitos resultados relacionados. Mesmo se houvesse, não houve muitas explicações detalhadas. Eu disse aproximadamente e, em seguida, dei um link para a especificação do ECMAScript. Parece que, se você quiser saber o verdadeiro motivo, só poderá morder a bala e olhar para as normas.
Padrões relacionados
Então, de acordo com a prática internacional, vá primeiro ao edifício da cidade padrão do ECMAScript.
A cópia do código é a seguinte:
String.prototype.split (separador, limite)
Este capítulo apresenta as etapas de execução do método dividido em detalhes. Se você estiver interessado, pode lê -lo cuidadosamente passo a passo. Vou explicar apenas as etapas relacionadas à geração de seqüências vazias aqui. Se houver pontos inadequados, todos poderão mencioná -los.
Etapas relacionadas
Etapas parciais para extrair:
A etapa mais importante em todo o processo é o 13º ciclo, e as principais coisas que esse ciclo faz são as seguintes:
• Defina os valores de p e q. Os valores de p e q são os mesmos no início de cada loop (esta etapa está fora do loop);
• Ligue para SplitMatch (S, Q, R) Método para dividir a string;
• Executar ramos diferentes de acordo com os resultados retornados, e os principais ramos são ramificações;
• O ramo é dividido em 8 pequenos passos para preencher o resultado retornado na matriz predefinida a
• Neste 8 pequenas etapas, o objetivo da etapa 1 é retornar uma substring da string original, a posição inicial é p (incluída) e a posição final é Q (incluída). Nota: Nesta etapa, uma sequência vazia será gerada e a marquei como interceptando a string para a conveniência de citar abaixo.
• Adicione a substring da etapa anterior para matar um
• As próximas etapas são atualizar as variáveis relevantes e continuar o próximo loop. (O objetivo da Etapa 7 é salvar o agrupamento de captura na expressão regular na matriz A, que não tem nada a ver com a geração de uma corda vazia)
SplitMatch (s, q, r)
Em seguida, precisamos entender o que o método SplitMatch (S, Q, R) faz. Este método é mencionado abaixo na especificação dividida. O que faz principalmente é executar operações correspondentes de acordo com o tipo de separador:
• Se o delimitador for do tipo regexp, ligue para o método interno da Regexp [[match]] para corresponder à sequência. Se a partida falhar, retorne a falha. Caso contrário, retorne um resultado de resultado.
• Se o delimitador for uma string, o julgamento da correspondência será realizado, a falha será retornada e o resultado do tipo de resultado será retornado com sucesso.
MatchResult
Nas etapas acima, uma variável de tipo de correspondência é introduzida. Ao procurar o documento, verificou -se que as variáveis desse tipo têm dois atributos endindex e capturas. O valor do endindex é a posição que corresponde à string mais 1. As capturas podem ser entendidas como uma matriz. Quando o delimitador é uma expressão regular, os elementos dentro dele são os valores capturados pelo grupo; Quando o delimitador é uma string, é uma matriz vazia.
Próximo
Podemos ver nas etapas acima que a sequência de divisão é gerada na etapa de interceptar a string (exceto a captura de grupo de expressões regulares). Sua função é interceptar a sequência entre o início especificado (incluído) e a posição final (incluída), então quando retornará ""? Há um caso especial em que os valores da posição inicial e a posição final são iguais, o que é apenas um palpite, porque a especificação não fornece as etapas de especificação para interceptar a string.
Todos nós viemos aqui, por que não dar um passo à frente?
Então, tentei procurar algum código -fonte do V8 para ver se conseguia encontrar um método de implementação específico. Eu encontrei o código relevante, link de código -fonte
Aqui estão alguns deles:
A cópia do código é a seguinte:
função stringsplitjs (separador, limite) {
...
...
// O delimitador é uma string
if (! is_regexp (separador)) {
var separator_string = to_string_inline (separador);
if (limite === 0) return [];
// ECMA-262 diz que, se o separador estiver indefinido, o resultado deve
// Seja uma matriz de tamanho 1 contendo a sequência inteira.
if (is_undefined (separador)) retornar [sujeito];
var separator_length = separator_string.length;
// O separador é uma corda vazia, que retorna diretamente a matriz de caracteres
if (separador_length === 0) return %stringtoArray (sujeito, limite);
var resultado = %stringsplit (sujeito, separador_string, limite);
resultado de retorno;
}
if (limite === 0) return [];
// Quando o delimitador é uma expressão regular, ligue para StringsplitonRegexp
retorno stringsplitonRegexp (sujeito, separador, limite, comprimento);
}
// Vários códigos são omitidos aqui
Encontrei no código que, ao preencher a matriz, o método %_Substring será chamado para interceptar a sequência. Infelizmente, não encontrei sua definição relevante. Se houver algum aluno que o encontrou, por favor me avise. No entanto, descobri que o método de estrutura de estrutura correspondente ao método de substring no JavaScript chamará o método %_substring e retornará o resultado. Então, se 'ABC'.Substring (1,1) retornar "", isso significa que o método %_Substring retornará "" quando a posição inicial e a posição final forem a mesma. Você pode dizer o resultado experimentando.
Então, quando a posição inicial igual à posição final (ou seja, q === P) ocorrer? Eu segui as etapas acima passo a passo e finalmente encontrei:
• Quando a string s original corresponde ao delimitador uma vez, imediatamente depois, a próxima posição da string s também corresponde ao delimitador. Por exemplo: 'abbbc'.split (' b '),' abbbc'.split (/(b) {1}/)
• Outro caso é que um ou vários caracteres no início de uma corda correspondem ao separador. Por exemplo: 'abc'.split (' a '),' abc'.split (/ab/)
• Há outro caso em que uma ou várias cordas no final da string corresponde ao delimitador, e a etapa relevante é a etapa 14.
Por exemplo: 'abc'.split (' c '),' abc'.split (/bc/)
Além disso, ao usar expressões regulares como delimitadores, a indefinição pode aparecer no resultado retornado.
Por exemplo: 'abc'.split (/(d)*/)
Vejamos o exemplo no início. Isso satisfaz as situações acima?
Fora do tópico
É a primeira vez que leio as especificações padrão do ECMAScript com muito cuidado. O processo de leitura é realmente muito doloroso, mas depois de entendê -lo, sinto -me muito feliz. Obrigado por esta pergunta e pela pergunta de acompanhamento.
A propósito, quando uma expressão regular é usada como separador, o modificador global G será ignorado, o que também é um ganho adicional.