elixir-lang / elixir

Elixir is a dynamic, functional language for building scalable and maintainable applications

Home Page:https://elixir-lang.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`(str == <<>>)` Results in false for empty strings in comprehensions

PsychicPlatypus opened this issue · comments

Elixir and Erlang/OTP versions

elixir 1.14.5-otp-25
erlang 25.0.4

Operating system

MacOS Sonoma 14.5 (23F79)

Current behavior

The following function:

def sanitize_string(text) do
    x =
      text
      |> String.replace(~r"\s+", " ")

    for i <- 0..(String.length(x) - 1)//2 do
      current = String.at(x, i) |> String.trim() |> tap(&IO.inspect(&1, label: ""))
      next = String.at(x, i + 1) |> String.trim() |> tap(&IO.inspect(&1, label: ""))

      (current == <<>>)
      |> tap(&IO.inspect(&1, label: ""))

      (next == <<>>)
      |> tap(&IO.inspect(&1, label: ""))
    end
  end

For the string:

foo bar foo bar
\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣\n⁣FII Institute⁣\n#Site,\n##"

Produces results:

...
: ""
: "⁣"
: true
: false
: ""
: "⁣"
: true
: false
: ""
: "⁣"
: true
: false
...

Which is not correct since both strings are empty, so they should both return true for the check str == <<>>

Expected behavior

The function should produce:

...
: ""
: "⁣"
: true
: true
: ""
: "⁣"
: true
: true
: ""
: "⁣"
: true
: true
...

For those empty strings

These are actually non-empty strings, they contain this invisible separator codepoint:

s = "⁣"
String.length(s) # 1
String.to_charlist(s) # [8291]
Integer.to_string(8291, 16)  # "2063"
s == "\u2063"  # true

Closing this as there is no bug in Elixir, but we may want to improve the printing in Elixir to make these cases clearer. :)

[notes] By comparison in python:

  • the representation is '\u2063' => we might be able to do the same for inspect
  • when copy-pasting in a python shell, "⁣" gets replaced by "\u2063"