Wejście:
Hello world👩🦰👩👩👦👦
Pożądane wyjście:
👩👩👦👦👩🦰dlrow olleH
Próbowałem kilku podejść, ale żadna nie dała mi poprawnej odpowiedzi.
To się nie udało:
const text = 'Hello world👩🦰👩👩👦👦';
const reversed = text.split('').reverse().join('');
console.log(reversed);
Ten rodzaj działa, ale dzieli się 👩👩👦👦
na 4 różne emoji:
const text = 'Hello world👩🦰👩👩👦👦';
const reversed = [...text].reverse().join('');
console.log(reversed);
Spróbowałem też każdej odpowiedzi na to pytanie, ale żadna z nich nie działa.
Czy istnieje sposób na uzyskanie pożądanego wyniku?
javascript
string
emoji
Hao Wu
źródło
źródło
�
postacie, a następnie jest dodatkowy znak łączący, którym jest kod 8205, a następnie są kolejne dwa , które reprezentują „rude włosy” i te 5 znaków razem oznacza „Odpowiedzi:
Jeśli możesz, użyj
_.split()
funkcji dostarczonej przez lodash . Począwszy od wersji 4.0 ,_.split()
jest w stanie rozdzielić emoji Unicode.Używanie natywnego
.reverse().join('')
do odwracania `` znaków '' powinno działać dobrze z emoji zawierającymi łączniki o zerowej szerokościfunction reverse(txt) { return _.split(txt, '').reverse().join(''); } const text = 'Hello world👩🦰👩👩👦👦'; console.log(reverse(text));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
źródło
reverse("뎌쉐")
(2 koreańskie grafemy), co daje „ᅰ셔 ᄃ” (3 grafemy).Wziąłem pomysł TKoL na użycie
\u200d
postaci i użyłem go do stworzenia mniejszego skryptu.Uwaga: nie wszystkie kompozycje używają łącznika o zerowej szerokości, więc będzie on zawierał błędy z innymi znakami kompozycji.
Używa tradycyjnej
for
pętli, ponieważ pomijamy niektóre iteracje w przypadku znalezienia połączonych emotikonów. Wewnątrzfor
pętli znajduje sięwhile
pętla sprawdzająca, czy jest następny\u200d
znak. Dopóki istnieje jeden, dodajemy również kolejne 2 znaki i przekazujemyfor
pętlę 2 iteracjami, aby połączone emotikony nie zostały odwrócone.Aby łatwo użyć go na dowolnym łańcuchu, stworzyłem go jako nową funkcję prototypową w obiekcie string.
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());
źródło
👩👩👦👦
można go zaznaczyć tylko jako całość. Skąd przeglądarki wiedzą, że to jeden znak? Czy jest na to wbudowany sposób?Odwracanie tekstu Unicode jest trudne z wielu powodów.
Po pierwsze, w zależności od języka programowania, łańcuchy są reprezentowane na różne sposoby, albo jako lista bajtów, lista jednostek kodu UTF-16 (szerokość 16 bitów, często nazywane „znakami” w API) lub jako punkty kodowe ucs4 (Szerokość 4 bajty).
Po drugie, różne interfejsy API odzwierciedlają tę wewnętrzną reprezentację w różnym stopniu. Niektórzy pracują nad abstrakcją bajtów, inni na znakach UTF-16, inni na punktach kodowych. Gdy reprezentacja używa bajtów lub znaków UTF-16, zwykle istnieją części interfejsu API, które zapewniają dostęp do elementów tej reprezentacji, a także części, które wykonują niezbędną logikę, aby uzyskać z bajtów (przez UTF-8) lub z UTF-16 znaków do rzeczywistych punktów kodowych.
Często części API wykonujące tę logikę, a tym samym dające dostęp do punktów kodowych, były dodawane później, ponieważ najpierw było 7-bitowe ascii, a nieco później wszyscy myśleli, że wystarczy 8 bitów, używając różnych stron kodowych, a nawet później, że 16 bitów wystarczyło dla Unicode. Pojęcie punktów kodowych jako liczb całkowitych bez ustalonej górnej granicy było historycznie dodawane jako czwarta wspólna długość znaku do logicznego kodowania tekstu.
Korzystanie z interfejsu API, który zapewnia dostęp do rzeczywistych punktów kodowych, wydaje się być tym. Ale...
Po trzecie, istnieje wiele modyfikatorów punktów kodowych wpływających na następny punkt kodowy lub kolejne punkty kodowe. Np. Istnieje modyfikator diakrytyczny zamieniający następujące po a w ä, e na ë i c. Obróć punkty kodowe, a aë stanie się eä, złożone z różnych liter. Istnieje bezpośrednia reprezentacja np. Ä jako własnego punktu kodowego, ale użycie modyfikatora jest równie ważne.
Po czwarte, wszystko jest w ciągłym ruchu. Wśród emoji jest również wiele modyfikatorów, jak użyto w przykładzie, a co roku jest ich więcej. Dlatego jeśli interfejs API zapewnia dostęp do informacji, czy punkt kodowy jest modyfikatorem, wersja interfejsu API określi, czy zna już określony nowy modyfikator.
Unicode zapewnia jednak sprytną sztuczkę, gdy chodzi tylko o wygląd:
Istnieją modyfikatory kierunku pisania. W przykładzie zastosowano kierunek pisania od lewej do prawej. Po prostu dodaj modyfikator kierunku pisania od prawej do lewej na początku tekstu iw zależności od wersji API / przeglądarki będzie wyglądał poprawnie odwrócony 😎
„\ u202e” nazywa się przesłonięciem od prawej do lewej, jest to najsilniejsza wersja znacznika od prawej do lewej.
Zobacz to wyjaśnienie w3.org
const text = 'Hello world👩🦰👩👩👦👦' console.log('\u202e' + text)
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))
body { font-family: sans-serif }
<p id="original"></p> <p id="result"></p>
źródło
'\u202e' + text + '\u202c'
aby uniknąć wpływu na następujący tekst.Wiem! Użyję RegExp. Co mogłoby pójść źle? (Odpowiedź pozostawiona jako ćwiczenie dla czytelnika).
const text = 'Hello world👩🦰👩👩👦👦'; const reversed = text.match(/.(\u200d.)*/gu).reverse().join(''); console.log(reversed);
źródło
.
symboli wieloznacznych).U+200D
np🏳️🌈
. Warto zauważyć, że skomponowane postacie istnieją również poza światem Emijoi…U+200D
. Łatwo sprawdzić, czy 🏳️🌈 nie działa z kodem tej odpowiedzi…Alternatywnym rozwiązaniem byłoby użycie
runes
biblioteki, małego, ale skutecznego rozwiązania: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"
źródło
Masz problem nie tylko z emoji, ale także z innymi łączącymi się postaciami. Te rzeczy, które wyglądają jak pojedyncze litery, ale w rzeczywistości są jednym lub więcej znakami Unicode, nazywane są „rozszerzonymi klastrami grafemów”.
Podział łańcucha na te klastry jest trudny (na przykład zobacz te dokumenty unicode ). Nie polegałbym na samodzielnym wdrożeniu, ale korzystałbym z istniejącej biblioteki. Google wskazał mi bibliotekę rozdzielaczy grafemów . Dokumentacja tej biblioteki zawiera kilka fajnych przykładów, które mogą potykać się z większością implementacji:
Używając tego powinieneś być w stanie napisać:
var splitter = new GraphemeSplitter(); var graphemes = splitter.splitGraphemes(string); var reversed = graphemes.reverse().join('');
POZA STRONĄ: Dla gości z przyszłości lub tych, którzy chcą żyć na krawędzi:
Istnieje propozycja dodania programu do segmentacji grafemów do standardu javascript. (W rzeczywistości zapewnia również inne opcje segmentacji). Obecnie znajduje się na 3 etapie przeglądu do akceptacji i jest obecnie wdrażany w JSC i V8 (patrz https://github.com/tc39/proposal-intl-segmenter/issues/114 ).
Używając tego kod wyglądałby następująco:
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('');
Prawdopodobnie możesz zrobić to schludniej, jeśli znasz bardziej nowoczesny javascript niż ja ...
Jest tu implementacja - ale nie wiem, czego ona wymaga.
Uwaga: wskazuje to na zabawny problem, którego inne odpowiedzi jeszcze nie rozwiązały. Segmentacja może zależeć od używanego ustawienia narodowego - nie tylko od znaków w ciągu.
źródło
const graphemes = Array.from(segment_iterator, ({segment}) => segment)
.Po prostu postanowiłem zrobić to dla przyjemności, było to dobre wyzwanie. Nie jestem pewien, czy jest poprawny we wszystkich przypadkach, więc używaj na własne ryzyko, ale oto jest:
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();
źródło
Możesz użyć:
yourstring.split('').reverse().join('')
Powinien przekształcić Twój ciąg w listę, odwrócić go, a następnie ponownie przekształcić w ciąg.
źródło
const text = 'Witaj, świecie👩🦰👩👩👦👦';
const reverse = text.split (''). reverse (). join ('');
console.log (odwrócona);
źródło