Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Tanto a resposta do Gabriel Santos como a do mgibsonbr estão erradas (embora funcionem bem nalguns casos limitados que acabam por ser os mais comuns).
**Porque motivo estão errados?**
Unicode. Nos tempos ancestrais (ASCII), cada caracter ocupava um espaço constante, mas isso já não é verdade.
O JavaScript usa o sistema UTF-16, em que aquilo a que a maioria das pessoas associa a caracter é dividido em "code points", que por sua vez são divididos em "code units".
Um caracter pode ter um ou mais code point e cada code point pode ter um ou dois code units. O primeiro é o code point "principal" e os seguintes (opcionais) são modificadores que acrescentam algo ao caracter (exemplo: acentos).
Quando um code point ocupa dois code units em UTF-16, diz-se que o primeiro é o "High Surrogate" (ou lead surrogate) e o segundo é o "Low Surrogate" (ou trail surrogate).
Exemplo de um caracter que falha nas respostas apresentas: o caracter 𝒞͆.
O caracter que eu coloquei é constituido por dois code points: O caracter 𝒞 e o modificador ͆ .
O code point 𝒞, por sua vez, ocupa dois code units.
Se calcular o inverso de "Olá 𝒞 ͆!" com as outras funções vai obter !͆ �� ́alO, que é claramente o resultado errado.
**A solução**
A solução completa ([jsfiddle de teste][1]) é a seguinte:
String.prototype.isHighSurrogate = function () {
var charCode = this.charCodeAt(0);
return charCode >= 0xD800 && charCode <= 0xDBFF;
}
String.prototype.isCombining = function () {
if (this.length != 1) {
//Todos os caracteres de combinação estão no BMP
return false;
}
var codePoint = this.charCodeAt(0);
//Combining Diacritical Marks
if (codePoint >= 0x0300 && codePoint <= 0x036F)
return true;
//Combining Diacritical Marks Supplement
if (codePoint >= 0x1DC0 && codePoint <= 0x1DFF)
return true;
//Combining Diacritical Marks for Symbols
if (codePoint >= 0x20D0 && codePoint <= 0x20FF)
return true;
//Combining Half Marks
if (codePoint >= 0xFE20 && codePoint <= 0xFE2F)
return true;
return false;
}
String.prototype.codePoints = function () {
var codePoints = [];
var currentPoint = '';
for (var i = 0; i < this.length; ++i) {
var currentUnit = this[i];
currentPoint += currentUnit;
if (!currentUnit.isHighSurrogate()) {
currentPoint = currentPoint;
codePoints.push(currentPoint);
currentPoint = '';
}
}
return codePoints;
}
String.prototype.chars = function () {
var chars = [];
var codePoints = this.codePoints();
var currentChar = '';
for (var i = 0; i < codePoints.length; ++i) {
var codePoint = codePoints[i];
if (!codePoint.isCombining()) {
chars.push(currentChar);
currentChar = '';
}
currentChar += codePoint;
}
chars.push(currentChar);
return chars;
}
String.prototype.reverse = function () {
return this.chars().reverse().join('');
}
Para usar o código acima, use `"String a inverter".reverse()`.
[1]: http://jsfiddle.net/E6yb8/1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.