Как я могу вернуть true, только если совпадает одна из набора строк? - PullRequest
4 голосов
/ 11 ноября 2019

Я хочу вернуть true, если пользователь вводит только одно из множества возможных совпадений. Подобно оператору XOR, но во входе может существовать только одна строка из всей группы. Вот мой код:

if input.match?(/str|con|dex|wis|int|cha/)

Следующие input s должны возвращать true:

+2 int
-3con
str
con
wisdom
dexterity

Следующие input s должны возвращать false:

+1 int +2 cha
-4dex+3con-1cha
int cha
str dex
con wis cha
strength intelligence
strdex

Ответы [ 3 ]

7 голосов
/ 11 ноября 2019

Я бы, наверное, выбрал String#scan и простое регулярное выражение, чтобы вы могли понять, что вы сделали позже:

if input.scan(/str|dex|con|int|wis|cha/).length == 1
  # Found exactly one
else
  # Didn't find it or found too many
end

Это также облегчает распознаваниемежду различными способами это может не сработать.

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

5 голосов
/ 11 ноября 2019

Ниже приведены три способа ответить на вопрос без создания промежуточного массива. Все используют регулярное выражение:

R = /str|con|dex|wis|int|cha/

и возвращают следующее:

one_match? "It wasn't a con, really"              #=> true 
one_match? "That sounds to me like a wild guess." #=> falsy (nil or false) 
one_match? "Both int and dex are present."        #=> falsy (nil or false) 
one_match? "Three is an integer."                 #=> true 
one_match? "Both int and indexes are present."    #=> falsy (nil or false) 

# 1 Начало первого и последнего совпадения начинается с одного индекса?

def one_match?(s)
  (idx = s.index(R)) && idx == s.rindex(R)
end

См. String # index и String # rindex .

# 2 Использовать форму String#index, которая принимает аргументравен индексу, с которого начинается поиск.

def one_match?(s)
  s.index(R) && s.index(R, Regexp.last_match.end(0)).nil?
end

См. Regexp :: last_match и MatchData # end . Regexp.last_match можно заменить на $~.

# 3. Использовать форму String # gsub , которая принимает один аргумент и не содержит блока, чтобы создать перечислитель, генерирующий совпадения

def one_match?(s)
  s.gsub(/str|con|dex|wis|int|cha/).count { true } == 1
end

См. Перечислимый # count .

Совпадение только с целыми словами

В предпоследнем примере 'int' соответствует 'int' в 'integer' и в последнем матче 'dex' соответствует 'dex' в 'indexes'. Для обеспечения соответствия полных слов регулярное выражение можно изменить на:

/\b(?:str|con|dex|wis|int|cha)\b/
3 голосов
/ 11 ноября 2019

Если вам нужно использовать регулярное выражение, вы можете использовать

/\A(?!(?:.*(str|con|dex|wis|int|cha)){2}).*\g<1>/m

См. Демо регулярное выражение

Подробно

  • \A - начало строки
  • (?!(?:.*(str|con|dex|wis|int|cha)){2}) - нет двух вхождений любых 0+ символов с последующими str, con, dex, wis, int, cha
  • .* - любые 0+ символов как можно больше
  • \g<1> - шаблон группы 1 (str, con, dex, wis, int или cha).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...