2013-02-11 47 views
2

我試圖想出一個簡單的方法來使用Ruby來打亂(或掩蓋)一些數字數據,以便從實時數據創建一個虛擬數據集。我想保持數據儘可能接近原始格式(即保留所有非數字字符)。數據中的數字對應於個人識別號碼,這些號碼(有時)是關係數據庫中使用的密鑰。所以,如果數字字符串多次出現,我想將其一致映射到相同(理想唯一)值。一旦數據被加擾,我不需要能夠反轉加擾。使用Ruby來替換數字數據使用簡單的哈希映射

我創建了一個爭奪函數,它接受一個字符串並生成一個簡單的哈希值以將數字映射爲新值(函數僅映射數字並保留其他所有內容)。爲了增加安全性,每次調用函數時,都會重新生成密鑰。因此,每次調用該函數時,相同的短語都會產生兩個不同的結果。

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"} 

[順便說一句,在我的例子,我還沒有找到一種方法來堅持的哈希值都是唯一的,這是相關事件的字符串被映射到對應一個唯一的ID在關係數據庫,如上所述。]

我在我的原始字符串上使用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

除了輝煌@澤的回答我會建議你

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

此實現引入了一個類變量,而不是一個實例之一:直接在String類(使str.scramble項目範圍提供的w/o丟棄任何額外行屈膝禮)至「注入」這個擾頻方法。如果您需要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