Я пытаюсь отобразить массив слов из сообщения пользователя. Однако метод, который я использую, обрабатывает апостроф как пробел.

<%= var = Post.pluck(:body) %>
<%= var.join.downcase.split(/\W+/) %>

Итак, если введенный текст был: The baby's foot
он выведет the baby s foot,
но это должно быть the baby's foot.

Как мне этого добиться?

-3
tickyt23 30 Дек 2015 в 20:17

4 ответа

Лучший ответ

Вы можете использовать ниже RegEx вместо /\W+/

var.join.downcase.split(/[^'\w]+/)

/\W/ относится ко всем символам, не являющимся словами, апостроф - это один из таких символов, не являющихся словами. Чтобы сохранить код как можно ближе к исходному замыслу, мы можем использовать /[^'\w]/ - это означает, что все символы, не являющиеся апострофом и символом слова.

0
Mogsdad 30 Дек 2015 в 18:02

Если пропустить эту строку через irb с тем же вызовом split, который вы написали в своем комментарии, мы получим следующее:

irb(main):008:0> "The baby's foot".split(/\W+/)
=> ["The", "baby", "s", "foot"]

Однако, если вы используете split без явного разделителя, вы получите нужное разделение:

irb(main):009:0> "The baby's foot".split
=> ["The", "baby's", "foot"]

Это дает вам то, что вы ищете?

0
Igor Ivancha 30 Дек 2015 в 18:11

В соответствии с ответом мудасобвы, вот что \w и \W приносят на вечеринку:

chars = [*' ' .. "\x7e"].join
# => " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

Это обычные видимые символы нижнего ASCII, которые мы видим в коде. См. документацию по Regexp для Дополнительная информация.

Захват символов, соответствующих \w, возвращает:

chars.scan(/\w+/)
# => ["0123456789",
#     "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
#     "_",
#     "abcdefghijklmnopqrstuvwxyz"]

И наоборот, захват символов, которые не соответствуют \w или совпадают с \W:

chars.scan(/\W+/)
# => [" !\"\#$%&'()*+,-./", ":;<=>?@", "[\\]^", "`", "{|}~"]

\w определяется как [a-zA-Z0-9_], а это не то, что вы обычно называете "словесными" символами. Вместо этого они обычно являются символами, которые мы используем для определения имен переменных.

Если вы имеете дело только с символами нижнего ASCII, используйте класс символов

[a-zA-Z]

Например:

chars = [*' ' .. "\x7e"].join
lower_ascii_chars = '[a-zA-Z]'
not_lower_ascii_chars = '[^a-zA-Z]'
chars.scan(/#{lower_ascii_chars}+/)
# => ["ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"]
chars.scan(/#{not_lower_ascii_chars}+/)
# => [" !\"\#$%&'()*+,-./0123456789:;<=>?@", "[\\]^_`", "{|}~"]

Вместо того, чтобы определять свои собственные, вы можете воспользоваться определениями POSIX и свойства персонажа:

chars.scan(/[[:alpha:]]+/)
# => ["ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"]

chars.scan(/\p{Alpha}+/)
# => ["ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"]

Регулярные выражения всегда кажутся замечательной новой палочкой, которой можно взмахнуть при извлечении информации из строки, но, как и Ученики чародея выяснили, что они могут создать хаос, если их неправильно использовать или не понять.

Знание этого должно помочь вам писать более разумные шаблоны. Примените это к тому, что показано в документации, и вы сможете легко определить шаблон, который делает то, что вы хотите.

1
the Tin Man 30 Дек 2015 в 19:38

Принятый ответ слишком наивен:

▶ "It’s naïve approach".split(/[^'\w]+/)
#⇒ [
#  [0] "It",
#  [1] "s",
#  [2] "nai",
#  [3] "ve",
#  [4] "approach"
# ]

Это потому, что сейчас почти 2016 год, и многие пользователи могут захотеть использовать свои обычные имена, например, Хосе Остергаард. Как вы могли заметить, пунктуация - это не только апостроф.

▶ "It’s naïve approach".split(/[^'’\p{L}\p{M}]+/)
#⇒ [
#  [0] "It’s",
#  [1] "naïve",
#  [2] "approach"
# ]

Дополнительная литература: Свойства символа.

4
Aleksei Matiushkin 30 Дек 2015 в 18:13