Пробел Ruby не равен пробелу

В следующих инструкциях одно из пробелов получено из ввода пользователя (я скопировал символ пользователя с удаленной консоли Rails (поле ActiveRecord) и вставил его), а другой - с моей клавиатуры. Операторы возвращают false:

" " == " " # => false
" ".include? " " # => false

Есть идеи, почему / как это может происходить?

Попробуйте проверить их [" ".ord, " ".ord], если вы получите [32, 160], у вас есть пробел и неразрывный пробел.

Sebastian Palma 30.08.2018 04:44

UTF-8 или непечатаемые символы, возможно. То, что это выглядит как пространство, не означает, что это так. Еще одна причина никогда не доверять пользовательскому вводу!

Todd A. Jacobs 30.08.2018 04:50

Себастьян, вот и все, я подумал, что это какая-то проблема с кодировкой. Спасибо.

Anthony L 30.08.2018 04:54
«Я подумал, что это какая-то проблема с кодировкой» - это ни в коем случае не проблема с кодировкой. Пользователь ввел неразрывный пробел. Сегодня умные люди настраивают свои клавиатуры, чтобы иметь возможность печатать типографически правильные вещи, такие как правильные «кавычки» и «апострофы», вместо того, что пишут на пишущей машинке. Также пробелы, тире, длинное тире и даже сердечки ❤.
Aleksei Matiushkin 30.08.2018 06:07

Невозможно воспроизвести.

sawa 30.08.2018 07:58

Синтаксический анализатор @sawa SO преобразует любое пространство в обычный ASCII, поэтому нет возможности правильно вставить его сюда. Хотя, вопрос описан хорошо.

Aleksei Matiushkin 30.08.2018 08:05

@mudasobwa Понятно.

sawa 30.08.2018 08:06

@sawa извините, не какой пробел :) только nbsp. Пробелы в моем ответе сохранены. Я заменю OP на один из них, чтобы проблема была воспроизводимой. → готово, теперь это воспроизводимо.

Aleksei Matiushkin 30.08.2018 08:08
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
1
8
1 645
2

Ответы 2

Чтобы проверить ввод данных пользователем для пустота, не следует использовать помощники == и / или include?. Следует использовать современное регулярное выражение, которое соответствует пробелы.

К вашему сведению: в спецификациях UTF-8 более десяти символов пробела, включая, но не ограничиваясь:

spaces = {
  space_medium_mathematical_space: " ",
  spaces_em_quad: " ",
  spaces_em_space: " ",
  spaces_en_quad: " ",
  spaces_en_space: " ",
  spaces_figure_space: " ",
  spaces_four_per_em_space: " ",
  spaces_hair_space: " ",
  spaces_punctuation_space: " ",
  spaces_six_per_em_space: " ",
  spaces_thin_space: " ",
  spaces_three_per_em_space: " "
}

Чтобы сопоставить их, используется сопоставитель \p{Space}.

spaces.values.map { |s| s == ' ' }
#⇒ [false, false, false, false, false, false,
#   false, false, false, false, false, false]

Но:

spaces.values.map(&/\A\p{Space}*\z/.method(:match?))
#⇒ [true, true, true, true, true, true,
#   true, true, true, true, true, true]

Предупреждение Nitpick: вы имели в виду спецификации Unicode. UTF-8 этого не говорит, например 8200 - это пробел, просто для его представления следует использовать байты 226, 128 и 136.

Amadan 30.08.2018 09:54
unicode.org/versions/Unicode11.0.0/ch06.pdf (стр. 264) содержит таблицу с доступными пробелами и некоторым описанием.
Stefan 30.08.2018 09:58

@ Амадан действительно. FWIW: приведенный выше фрагмент пробелов взят из моего любимого проекта Elixir StringNaming, где я анализирую unicode.org/Public/10.0.0/ucd/NamesList.txt из спецификаций Unicode, чтобы получить имена и значения.

Aleksei Matiushkin 30.08.2018 10:03

Я считаю, что вы можете использовать Строка # unicode_normalize. У него есть несколько форм нормализации, которые задокументированы в unicode.org. Похоже, для этой цели подходят :nfkc и :nfkd.

s = "foo bar" # <-- includes a non breaking space
space = " "   # <-- regular space

s.include?(space)                          # => false
s.unicode_normalize(:nfkc).include?(space) # => true

Другие вопросы по теме