Вы можете смешать отрицательный взгляд в свой BL
матчер:
/(.*[^-])-?(?:BK\/BL|BZ|(?<!BK\/)BL)/
Добавление (?<!BK\/)
означает, что вы хотите сопоставить BL
, за исключением случаев, когда ему предшествует BK/
.
Быстрый тест:
>> %w{23430-BL 23430GR 23430BK/BL}.map { |s| s[/(.*[^-])-?(?:BK\/BL|BZ|(?<!BK\/)BL)/,1] }
=> ["23430", nil, "23430"]
Ваш пример выходных данных не совпадает с вашим входом, является ли "GR" опечаткой в ваших входах или "BZ" опечаткой в вашем регулярном выражении?
Учитывая, что ваши шаблоны не являются фиксированными, вы можете полностью обойти регулярные выражения и вернуться к простой обработке строк. Вот лучший пример того, что я упомянул в своем комментарии:
require 'set'
# The suffix list that you get from somewhere.
suffixes = [ 'BK/BL', 'BZ', 'BL' ]
# We want to do a couple things at once here. For each suffix, we
# want both the suffix and the suffix with a leading '-' attached,
# the `map` and `flatten` stuff does that. Then we group them by
# length to get a hash like:
#
# { 2 => ['BZ','BL'], 3 => ['-BZ', '-BL'], 5 => ['BK/BL'], ... }
#
by_length = suffixes.map { |suffix| [suffix, '-' + suffix ] }.flatten.group_by(&:length)
# Now we reorganize our suffixes into sets with the set of longest
# suffixes first and the set of shortest suffixes last. The result
# will be:
#
# [#<Set: {"-BK/BL"}>, #<Set: {"BK/BL"}>, #<Set: {"-BZ", "-BL"}>, #<Set: {"BZ", "BL"}>]
#
sets = by_length.keys.sort { |a,b| b <=> a }.map { |k| Set.new(by_length[k]) }
# Then we can just spin through sets, pull off the suffix of the
# appropriate length from the string, and see if it is in our set.
# If it is then chop the suffix off the string, do whatever is to be
# done with chopped string, and break out for the next string.
#
%w{ 23430-BL 23430BZ 23430BK/BL }.each do |string|
sets.each do |suffixes|
len = suffixes.first.length
sfx = string[string.length - len, len]
if(suffixes.include?(sfx))
puts string[0 .. -(len + 1)]
break
end
end
end
Это просто иллюстрация алгоритма "с головы до головы".