2013-02-11 2 views
2

Я пытаюсь придумать простой способ использования Ruby для скремблирования (или маскировки) некоторых числовых данных, чтобы создать фиктивный набор данных из живых данных. Я хочу сохранить данные как можно ближе к исходному формату (т. Е. Сохранить все нечисловые символы). Номера в данных соответствуют индивидуальным идентификационным номерам, которые (иногда) являются ключами, используемыми в реляционной базе данных. Итак, если числовая строка встречается более одного раза, я хочу последовательно ее сопоставить с тем же (идеально уникальным) значением. После того, как данные были скремблированы, мне не нужно менять скремблирование.Использование Ruby для замены числовых данных с помощью простой hashmap

Я создал функцию скремблирования, которая берет строку и генерирует простой хеш для сопоставления чисел с новыми значениями (функция только отображает числовые цифры и оставляет все остальное как есть). Для дополнительной безопасности каждый раз, когда вызывается функция, ключ восстанавливается. Таким образом, одна и та же фраза будет вызывать два разных результата при каждом вызове функции.

module HashModule 
    def self.scramble(str) 
    numHash ={} 
    0.upto(9) do |i| 
     numHash[i.to_s]=rand(10).to_s 
    end 

    output= String.new(str) 
    output.gsub!(/\d/) do|d| 
     d.replace numHash[d] 
    end 

    puts "Input: " + str 
    puts "Hash Key: " + numHash.to_s 
    puts "Output: " + output 
    end 
end 

HashModule.scramble("56609-8 NO PCT 001") 
HashModule.scramble("56609-8 NO PCT 001") 

Это производит следующий вывод:

Input: 56609-8 NO PCT 001 
Hash Key: {"0"=>"9", "1"=>"4", "2"=>"8", 
      "3"=>"9", "4"=>"4", "5"=>"8", 
      "6"=>"4", "7"=>"0", "8"=>"2", 
      "9"=>"1"} 
Output: 84491-2 NO PCT 994 

Input: 56609-8 NO PCT 001 
Hash Key: {"0"=>"2", "1"=>"0", "2"=>"9", 
      "3"=>"8", "4"=>"4", "5"=>"5", 
      "6"=>"7", "7"=>"4", "8"=>"2", 
      "9"=>"0"} 
Output: 57720-2 NO PCT 220 

Данный набор данных:

PTO NO PC 
R5632893423 IP 
R566788882-001 
NO PCT AMB PTO 
NO AMB/CALL IP 
A566788882 
1655543AACHM IP 
56664320000000 
00566333-1 

Я первый извлечь все числа в массиве. Затем я использую функцию скремблирования, созданную мной для создания хеш-карты замены, например.

{"5632893423"=>"5467106076", "566788882"=>"888299995", 
    "001"=>"225", "1655543"=>"2466605", 
    "56664320000000"=>"70007629999999", 
    "00566333"=>"00699999", "1"=>"3"} 

[Кстати, в моем примере, я не нашел способ настоять, что хэш-значения являются уникальными, что актуально в случае, если строка, в которой отображается соответствует уникальному идентификатору в базе данных отношений , как описано выше.]

Я использую gsub на своей исходной строке и заменяю хэш-ключи с помощью скремблированного значения. В коде у меня есть работы, но мне любопытно узнать, как я могу сделать его более кратким. Я понимаю, регенерируя ключ каждый раз, когда вызывается функция, я создаю дополнительную работу. (В противном случае я мог бы просто создать один ключ для замены всех цифр).

Есть ли у кого-нибудь предложения, как я могу это сделать другим способом? (Я новичок в Ruby, поэтому предложения по улучшению моего кода также очень получаются).

input = <<EOS 
PTO NO PC 
R5632893423 IP 
R566788882-001 
NO PCT AMB PTO 
NO AMB/CALL IP 
A566788882 
1655543AACHM IP 
56664320000000 
00566333-1 
EOS 

module HashModule 
    def self.scramble(str) 
    numHash ={} 
    0.upto(9) do |i| 
     numHash[i.to_s]=rand(10).to_s 
    end 

    output= String.new(str) 
    output.gsub!(/\d/) do|d| 
     d.replace numHash[d] 
    end 
    return output 
    end 
end 

# Extract unique non-null numbers from the input file 
numbers = input.split(/[^\d]/).uniq.reject{ |e| e.empty? } 

# Create a hash that maps each number to a scrambled value 
# Using the function defined above 

mapper ={} 
numbers.map(&:to_s).each {|x| mapper[x]=HashModule.scramble(x)} 

# Create a regexp to find all numbers in input file 
re = Regexp.new(mapper.keys.map { |x| Regexp.escape(x) }.join('|')) 

# Replace numbers with scrambled values 
puts input.gsub(re, mapper) 

Приведенный выше код производит следующий вывод:

PTO NO PC 
R7834913043 IP 
R799922223-772 
NO PCT AMB PTO 
NO AMB/CALL IP 
A799922223 
6955509AACHM IP 
13330271111111 
66166777-6 

ответ

1

Может быть что-то вроде этого:

module HashModule 
    ScrambleKey = Hash[(0..9).map(&:to_s).zip((0..9).to_a.shuffle)] 
    def self.scramble(str); str.gsub(/\d/){ScrambleKey[$&]} end 
end 

puts HashModule.scramble(input) 

, который дает:

PTO NO PC 
R6907580170 IP 
R699455557-223 
NO PCT AMB PTO 
NO AMB/CALL IP 
A699455557 
3966610AACHM IP 
69991072222222 
22699000-3 
1

В дополнение к блестящей @ Саввы ответ Я бы предложил вам чтобы «придать» этот метод скремблирования непосредственно в String класса (изготовление str.scramble проекта шириной доступны без падения каких-либо дополнительных реверансов):

class String 
    @@ScrambleKey = Hash[(0..9).map(&:to_s).zip((0..9).to_a.shuffle)] 
    def scramble ; self.gsub(/\d/) { @@ScrambleKey [$&] } end 
end 

Эта реализация вводит переменную класса, а не экземпляр одного. Если вам нужно, чтобы ScrambleKey отличался от String to String, вместо этого используйте переменную экземпляра.

Уступая:

input = <<EOS 
PTO NO PC 
R5632893423 IP 
R566788882-001 
NO PCT AMB PTO 
NO AMB/CALL IP 
A566788882 
1655543AACHM IP 
56664320000000 
00566333-1 
EOS 

puts input.scramble 

дает:

PTO NO PC 
R1548024784 IP 
R155600008-339 
NO PCT AMB PTO 
NO AMB/CALL IP 
A155600008 
9511174AACHM IP 
15557483333333 
33155444-9 
Смежные вопросы