Hao*_* Wu 197 javascript string emoji
Hello world????
Run Code Online (Sandbox Code Playgroud)
????dlrow olleH
Run Code Online (Sandbox Code Playgroud)
我尝试了几种方法,但没有一个给我正确的答案。
这惨败:
Hello world????
Run Code Online (Sandbox Code Playgroud)
这有点有效,但它???
分为 4 个不同的表情符号:
????dlrow olleH
Run Code Online (Sandbox Code Playgroud)
我也尝试了这个问题中的所有答案,但没有一个有效。
有没有办法获得所需的输出?
0st*_*ne0 96
如果可以,请使用lodash_.split()
提供的功能。从4.0 版开始,能够拆分 unicode 表情符号。_.split()
使用原.reverse().join('')
生来反转“字符”应该可以很好地处理包含零宽度连接符的表情符号
function reverse(txt) { return _.split(txt, '').reverse().join(''); }
const text = 'Hello world????';
console.log(reverse(text));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
Run Code Online (Sandbox Code Playgroud)
Mar*_*ens 55
我采纳了 TkoL 使用\u200d
角色的想法,并用它来尝试创建一个较小的脚本。
注意:并非所有合成都使用零宽度连接器,因此其他合成字符会出现问题。
它使用传统的for
循环,因为我们会跳过一些迭代,以防我们找到组合的表情符号。在for
循环内有一个while
循环来检查是否有后续\u200d
字符。只要有一个,我们也添加接下来的 2 个字符,并for
用 2 次迭代转发循环,这样组合的表情符号就不会反转。
为了在任何字符串上轻松使用它,我将它作为字符串对象上的新原型函数。
String.prototype.reverse = function() {
let textArray = [...this];
let reverseString = "";
for (let i = 0; i < textArray.length; i++) {
let char = textArray[i];
while (textArray[i + 1] === '\u200d') {
char += textArray[i + 1] + textArray[i + 2];
i = i + 2;
}
reverseString = char + reverseString;
}
return reverseString;
}
const text = "Hello world????";
console.log(text.reverse());
//Fun fact, you can chain them to double reverse :)
//console.log(text.reverse().reverse());
Run Code Online (Sandbox Code Playgroud)
yeo*_*man 47
由于很多原因,反转 Unicode 文本很棘手。
首先,根据编程语言,字符串以不同的方式表示,可以是字节列表、UTF-16 代码单元列表(16 位宽,在 API 中通常称为“字符”)或 ucs4 代码点(4 个字节宽)。
其次,不同的 API 在不同程度上反映了这种内部表示。有些研究字节的抽象,有些研究 UTF-16 字符,有些研究代码点。当表示使用字节或 UTF-16 字符时,API 的某些部分通常可让您访问此表示的元素,以及执行必要逻辑以从字节(通过 UTF-8)或从UTF-16 字符到实际代码点。
通常,API 的部分执行该逻辑并因此使您可以访问代码点是后来添加的,因为最初有 7 位 ascii,然后稍后每个人都认为 8 位就足够了,使用不同的代码页,甚至后来 16 位对于 unicode 就足够了。代码点作为没有固定上限的整数的概念在历史上被添加为逻辑编码文本的第四个常见字符长度。
使用可让您访问实际代码点的 API 似乎就是这样。但...
第三,有很多修饰符代码点会影响下一个代码点或后续代码点。例如,有一个变音符号修饰符将 a 后面的 a 变成 ä、e 到 ë、&c。把代码点反过来,aë变成了eä,由不同的字母组成。例如 ä 可以直接表示为它自己的代码点,但使用修饰符同样有效。
第四,一切都在不断变化。表情符号中也有很多修饰符,如示例中所用,并且每年都会添加更多。因此,如果 API 允许您访问代码点是否为修饰符的信息,则 API 的版本将确定它是否已经知道特定的新修饰符。
不过,Unicode 提供了一个技巧,当它仅与视觉外观有关时:
有书写方向修饰符。在示例的情况下,使用从左到右的书写方向。只需在文本开头添加一个从右到左的书写方向修饰符,根据 API / 浏览器的版本,它看起来会正确反转
'\u202e' 被称为从右到左覆盖,它是从右到左标记的最强版本。
请参阅w3.org 的解释
const text = 'Hello world????'
console.log('\u202e' + text)
Run Code Online (Sandbox Code Playgroud)
const text = 'Hello world????'
console.log('\u202e' + text)
Run Code Online (Sandbox Code Playgroud)
const text = 'Hello world????'
let original = document.getElementById('original')
original.appendChild(document.createTextNode(text))
let result = document.getElementById('result')
result.appendChild(document.createTextNode('\u202e' + text))
Run Code Online (Sandbox Code Playgroud)
body {
font-family: sans-serif
}
Run Code Online (Sandbox Code Playgroud)
Nei*_*eil 39
我知道!我将使用正则表达式。什么可能出错?(答案留给读者作为练习。)
const text = 'Hello world????';
const reversed = text.match(/.(\u200d.)*/gu).reverse().join('');
console.log(reversed);
Run Code Online (Sandbox Code Playgroud)
Arn*_*aga 32
替代解决方案是使用runes
库,小而有效的解决方案:
https://github.com/dotcypress/runes
const runes = require('runes')
// String.substring
'???a'.substring(1) => '????a'
// Runes
runes.substr('???a', 1) => 'a'
runes('12???3?').reverse().join();
// results in: "?3???21"
Run Code Online (Sandbox Code Playgroud)
Mic*_*son 22
您不仅会遇到表情符号的问题,还会遇到其他组合字符的问题。这些感觉像是单个字母但实际上是一个或多个 unicode 字符的东西被称为“扩展字素簇”。
将字符串分成这些簇是很棘手的(例如,请参阅这些unicode docs)。我不会依赖自己实现它,而是使用现有的库。谷歌指给我看grapheme-splitter库。这个库的文档包含一些很好的例子,这些例子会绊倒大多数实现:
使用这个你应该能够写:
var splitter = new GraphemeSplitter();
var graphemes = splitter.splitGraphemes(string);
var reversed = graphemes.reverse().join('');
Run Code Online (Sandbox Code Playgroud)
旁白:对于来自未来的游客,或那些愿意生活在最前沿的人:
有一项建议将字素分段器添加到 javascript 标准中。(它实际上也提供了其他分割选项)。目前处于第 3 阶段接受审查,目前在 JSC 和 V8 中实现(参见https://github.com/tc39/proposal-intl-segmenter/issues/114)。
使用这个代码看起来像:
var segmenter = new Intl.Segmenter("en", {granularity: "grapheme"})
var segment_iterator = segmenter.segment(string)
var graphemes = []
for (let {segment} of segment_iterator) {
graphemes.push(segment)
}
var reversed = graphemes.reverse().join('');
Run Code Online (Sandbox Code Playgroud)
如果您比我了解更多现代 javascript,您可能会使它更整洁...
这里有一个实现- 但我不知道它需要什么。
注意:这指出了其他答案尚未解决的有趣问题。分段可能取决于您使用的语言环境 - 而不仅仅是字符串中的字符。
TKo*_*KoL 17
我只是为了好玩才决定这样做,这是一个很好的挑战。不确定它在所有情况下都是正确的,所以使用风险自负,但这里是:
function run() {
const text = 'Hello world????';
const newText = reverseText(text);
console.log(newText);
}
function reverseText(text) {
// first, create an array of characters
let textArray = [...text];
let lastCharConnector = false;
textArray = textArray.reduce((acc, char, index) => {
if (char.charCodeAt(0) === 8205) {
const lastChar = acc[acc.length-1];
if (Array.isArray(lastChar)) {
lastChar.push(char);
} else {
acc[acc.length-1] = [lastChar, char];
}
lastCharConnector = true;
} else if (lastCharConnector) {
acc[acc.length-1].push(char);
lastCharConnector = false;
} else {
acc.push(char);
lastCharConnector = false;
}
return acc;
}, []);
console.log('initial text array', textArray);
textArray = textArray.reverse();
console.log('reversed text array', textArray);
textArray = textArray.map((item) => {
if (Array.isArray(item)) {
return item.join('');
} else {
return item;
}
});
return textArray.join('');
}
run();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
13553 次 |
最近记录: |