Было бы неплохо иметь возможность написать:
str.gsub(/(.)[^\1]*\z/i, '')
, но, увы, обратные ссылки (\1
) не могут появляться в классах символов.
Не знаюЯ считаю, что цель может быть достигнута с помощью одного регулярного выражения, но она может быть реализована с помощью последовательности из них.Я предполагаю, что строка содержит только строчные буквы, например:
str = "bananas"
1.Преобразуйте буквы, которые следуют позже в строке той же буквой, в верхний регистр.
str1 = str.gsub(/(.)(?=.*\1)/) { |s| s.upcase }
#=> "bANAnas
2.Удалите строчные буквы.
str2 = str1.gsub(/\p{Ll}/, '')
#=> "ANA"
3.Удалите дубликаты оставшихся букв.
str3 = str2.gsub(/(.)(?=.*\1)/, '')
#=> "NA"
4.Вниз
str3
при желании.
str3.downcase
#=> "na"
(?=.*\1)
- это положительный прогноз .
Если требование использования регулярного выражения снято, можноwrite:
str.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }.
select { |_,count| count > 1 }.
keys
#=> ["a", "n"]
Здесь
str.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
#=> {"b"=>1, "a"=>3, "n"=>2, "s"=>1}
Используется вторая форма Hash :: new , которая принимает аргумент, называемый значение по умолчанию .h[c] += 1
расширяется до h[c] = h[c] + 1
.Если h
не имеет ключа c
, h[c]
справа от равенства возвращает значение по умолчанию, равное нулю, что приводит к h]c] = 0 + 1
.