Странности с gsub

Я пытался использовать gsub для удаления несловных символов в строке в приложении rails. Я использовал следующий код:

somestring.gsub(/[\W]/i, '')  #=> ""

но на самом деле это неверно, он также удалит букву k. Правильный должен быть:

somestring.gsub(/\W/i, '')  #=> "kkk"

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

it "test this gsub" do
  'kkk'.gsub(/[\W]/i, '').should == 'kkk'
end

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


person Ben    schedule 27.04.2012    source источник
comment
Почему тест провалится? Насколько я понимаю, /[\W]/i является полностью допустимым регулярным выражением для этой задачи. Скобки в этом случае не нужны, но они ничему не помешают.   -  person KL-7    schedule 27.04.2012
comment
Вы действительно пробовали свои регулярные выражения в irb? "kkk".gsub(..) работает как надо, результат ккк, значит тест пройден. Какой результат вы ожидаете?   -  person Casper    schedule 27.04.2012
comment
@Casper На самом деле, при запуске 'kkk'.gsub(/[\W]/i, '') я получаю "". Для сравнения, запуск 'kkk'.gsub(/\W/i, '') возвращает "kkk".   -  person Andrew Marshall    schedule 27.04.2012
comment
Э что? k — символ слова. А \W соответствует символам, не являющимся словами. В моей установке Ruby я получаю "kkk" при запуске в irb.   -  person Casper    schedule 27.04.2012
comment
@Casper Да, я знаю, это не имеет никакого смысла. У меня стоит 1.9.3-p194. 1.9.2-p318 ведет себя так же, но 1.8.7-p358 возвращает "kkk", как и ожидалось.   -  person Andrew Marshall    schedule 27.04.2012
comment
Мои извинения, я тестировал его на 1.8.7, где он работает, как и ожидалось. В версии 1.9 я получаю тот же результат, что и Эндрю Маршалл.   -  person KL-7    schedule 27.04.2012
comment
Да.. Я только что попробовал в 1.9, то же самое здесь. Ошибка?   -  person Casper    schedule 27.04.2012
comment
Похоже. Хотя все работает нормально, если убрать флаг /i. Вам действительно нужен флаг игнорирования регистра для символов, отличных от слов?   -  person KL-7    schedule 27.04.2012
comment
Хорошо, это довольно странно: 'jklfds'.gsub(/[\W]/i, '') дает "jlfd". Это регулярное выражение, кажется, действительно сбивает Ruby с толку.   -  person Andrew Marshall    schedule 27.04.2012
comment
Поведение подтверждено на 1.9.3p0   -  person steenslag    schedule 27.04.2012
comment
Забыл упомянуть, что моя рубиновая версия - ruby-1.9.3-p125.   -  person Ben    schedule 27.04.2012
comment
Мой вопрос в том, почему модульный тест пройдет. Если это ошибка языка ruby, то модульный тест не должен пройти, он должен провалиться.   -  person Ben    schedule 27.04.2012


Ответы (1)


Ruby 1.9 переключился на другой механизм регулярных выражений (Oniguruma), что объясняет изменение поведения. Это похоже на ошибку в нем.

В вашем примере вы можете обойти проблему, не указав совпадение без учета регистра:

irb(main):001:0> 'kkk'.gsub(/[\W]/i, '')
=> ""
irb(main):002:0> 'kkk'.gsub(/[\W]/, '')
=> "kkk"
irb(main):004:0> 'kkk'.gsub(/\W/i, '')
=> "kkk"
irb(main):003:0> 'kkk'.gsub(/\W/, '')
=> "kkk"

Обновление: похоже, что удаление группы символов — это еще один подход. Может быть, подобные отрицательные совпадения не обязательно действительны в группе символов?

person Nevir    schedule 27.04.2012
comment
Как вы думаете… нет, не может… он берет \W и делает его \w, потому что он нечувствителен к регистру? На самом деле этого не может быть, верно?? О_О - person Andrew Marshall; 27.04.2012
comment
Я надеюсь, что нет... Но кто знает. Вероятно, это следует поднять на bugs.ruby-lang.org, чтобы подтвердить, кто виноват - person Nevir; 27.04.2012
comment
Ошибка подтверждена и здесь rubular.com. Вы можете переключаться между 1.8.7 и 1.9.2 и видеть разницу. - person Casper; 27.04.2012
comment
@AndrewMarshall, я сомневаюсь, что это настолько глупо =) Кстати, /[\S]/i работает просто отлично. - person KL-7; 27.04.2012
comment
@KL-7 Да, но кто знает ;). И приятно, это несколько обнадеживает. - person Andrew Marshall; 27.04.2012
comment
Кстати, только что проверил это на Ruby 2.0 dev, и он все еще существует. - person Andrew Marshall; 27.04.2012
comment
Вот уже существующая ошибка Ruby по этому поводу. - person Andrew Marshall; 27.04.2012
comment
Боже, я не ожидал, что этот вопрос так популярен. Видимо, многие этого не знали. Спасибо за ответы! = Д - person Ben; 27.04.2012
comment
На самом деле я до сих пор не знаю, почему в тесте rspec код работает! Есть ли что-то особенное в gsub в тесте rspec? - person Ben; 27.04.2012
comment
Похоже, что это проблема, когда регулярные выражения находятся в режиме юникода - я предполагаю, что ваша оболочка рельсов имеет другую кодировку по умолчанию, чем ваша тестовая среда. - person Nevir; 27.04.2012