stefanluptak
Hi all!
I would like to ask for an ideas how to solve the different way JavaScript and Elixir are approaching Strings and indexes of characters.
I want to store the same (user entered) text on the Elixir and also the JavaScript side. I also want to exchange messages describing operations like {:delete, from, to}, {:insert, position, text}, etc. to ensure the same text is on both sides.
The thing is, that this becomes intersting as soon as the text contains some emojis, characters with puncutation and so on.
Working with strings (binaries) in Elixir is pretty straightforward. Unfortunately (but not surprisingly
), the JavaScript behavior is (in my opinion) a bit unintuitive.
// JavaScript
> String.fromCharCode(97, 769).slice(0, 1)
'a'
> String.fromCharCode(225).slice(0, 1)
'á'
# Elixir
iex> [97, 769] |> to_string() |> String.slice(0, 1)
"á"
iex> [225] |> to_string() |> String.slice(0, 1)
"á"
What strategy should I use? Should I work with the text as a charlist on the Elixir side or should I normalize all strings everywhere? Or is there a better strategy I should take a look at?
Thank you all for you advices.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #ai
- #iex
- #graphql
- #elixirconf-us
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
hauleth
Unicode is hard.
Unicode is very hard.
Unicode is enormously hard.
If you want to have consistent behaviour then operate on bytes. So you will use
BloborUint8Arrayon JS side and binaries on Elixir side. I think it would be the simplest way. I hope that what you are describing (as I assume you want to created distributed concurrent text editor) is CRDT like LSEQ.stefanluptak
Thank you for your reply @hauleth. I am not sure I understand your solution. I will try to write pseudo-code example:
This will delete the “b” too, because Elixir is considering “á” to be 1 character and doesn’t care how many codepoints it has:
From my point of view, it might be safe (on Elixir side) to convert all the strings to charlists and then use the
List/Enumoperations. Am I wrong?P.S.: Yes, the concurrent/distributed operations are handled with CRDT. It’s just this unicode stuff I am trying to solve.
NobbZ
The big question is, do you want to work on “graphemes” or on “codepoints”? If the latter, do you do normalize first?
The Javascript seems to operate on “codepoints”, though the current normalisation is unknown, if it normalises at all, instead of just taking what it gets from the operating system.
stefanluptak
NobbZ
Do you want to be
aand^be considered as separate or asâ?If the latter, work on graphemes.
Read docs of string functions carefully to know if they work on graphemes or codepoints.
The same is true for the JS functions and methods you use.
Though I have to disappoint you. It will be complicated, no matter what. Most developers of string handling libraries either do not care or even understand the differences.
Anyway, try to avoid random access of strings by codepoint or grapheme, it’s O(n) operation!
hauleth
Operate on bytes it is the safest way, so you do not use
Stringmodule in short. This will provide you independence form encoding of your data. So it would look like thisAnd then in Elixir:
Alternatively use LSEQ mentioned earlier which is representation independent (as it generates it’s own indices instead of using string positions).
stefanluptak
Thanks a lot. Now I understand.
stefanluptak
I tried to do a little benchmark here and I am quite surprised, that doing
binary_part(binary, from, length)is 46x faster thanEnum.slice(charlist, from, to)Of course doing
String.slice(string, from, to)is extremely slow. That’s not surprising.Do you have some tips to do that even faster?
benwilson512
Do what, binary_part? binary_part is about as fast as it gets on the BEAM for that specific operation I think.
stefanluptak
Yes, I meant that one. Sorry for not being clear enough. OK, good to know. Thanks.