HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Lua program to clean up phone numbers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
luanumbersprogramphoneclean

Problem

How idiomatic is my code? Since Lua does not have classical inheritance such as in OO languages. Feedback on the test and implementation are both appreciated/welcomed.

The rules are:

  • If the phone number is less than 10 digits assume that it is bad number



  • If the phone number is 10 digits assume that it is good



  • If the phone number is 11 digits and the first number is 1, trim the 1 and use the first 10 digits



  • If the phone number is 11 digits and the first number is not 1, then it is a bad number



  • If the phone number is more than 11 digits assume that it is a bad number



local PhoneNumber = {}

function PhoneNumber:new(no_as_string)
  self.__index = self
  local n = "0000000000"
  n = no_as_string:gsub("[^0-9]", "")
  if (n:len() == 11 and n:sub(1, 1) == "1") then 
    n = n:sub(2, 11)
  else 
    if (n:len() > 10 or n:len() < 10) then
      n = "0000000000"
    end
  end
  return setmetatable({ number = n }, self)
end

function PhoneNumber:areaCode(symbol)
  return self.number:sub(1, 3)
end

function PhoneNumber:toString(symbol)
  return "("..self.number:sub(1, 3)..") "..self.number:sub(4, 6).."-"..self.number:sub(7, 10)
end

return PhoneNumber


Here is the test:

```
local PhoneNumber = require('phone-number')

describe("PhoneNumber()", function()
it("cleans the number (123) 456-7890", function()
local phone = PhoneNumber:new("(123) 456-7890")
assert.are.equals(phone.number,"1234567890")
end)

it("cleans numbers with dots", function()
local phone = PhoneNumber:new("123.456.7890")
assert.are.equals(phone.number,"1234567890")
end)

it("valid when 11 digits and first digit is 1", function()
local phone = PhoneNumber:new("11234567890")
assert.are.equals(phone.number,"1234567890")
end)

it("invalid when 11 digits", function()
local phone = PhoneNumber:new("21234567890")
assert.are.equals(phone.number,"0000000000")
end)

it("invalid when 9 digits", function()
local phone = PhoneNumber:new("123456

Solution

You've a lot of unnecessary code. First off, as janos stated:

local n = "0000000000"
n = no_as_string:gsub("[^0-9]", "")




The initialization of n is pointless here.

You can instead use just the lua pattern to match your input to desired result:

function PhoneNumber:new( Number )
    local n = string.gsub( Number, "%D", "" )
    n = n:match "^1?(%d%d%d%d%d%d%d%d%d%d)$" or "0000000000"
    return setmetatable({ number = n, __index = self }, self)
end


Notice that I've changed the input argument to Number and later use string.gsub( Number.... This way; you've the advantage of inputting direct numbers and provide flexibility.

The pattern

"^1?(%d%d%d%d%d%d%d%d%d%d)$"


is self-explanatory. In lua, if string.match failed to find any matched group; it returns nil. I've used this property to check for bad numbers.

Next thing I'd suggest that you do is store the number as an integer instead of string:

return setmetatable({ number = tonumber(n), __index = self }, self)


This is just because integers take less memory than strings. For retrieving area code etc., use mathematical operations:

function PhoneNumber:areaCode()  -- what was symbol parameter for?
    return math.floor( self.number / 10^7 )
end


Lastly, lua provides a meta-method: __tostring for conversion to strings from other types. Use it (It is the reason why I was able to use string.gsub above):

function PhoneNumber:__tostring()
    local f, n = math.floor, self.number
    local sFormat, iPart1, iPart2 = "(%d) %d-%d", f( n / 10^7 ), f( n / 10^3 % 10^4 )
    return sFormat:format( self:areaCode(), iPart1, iPart2 )
end


Now, instead of calling PhoneObject:toString(), you can do:

tostring( PhoneObject )

Code Snippets

local n = "0000000000"
n = no_as_string:gsub("[^0-9]", "")
function PhoneNumber:new( Number )
    local n = string.gsub( Number, "%D", "" )
    n = n:match "^1?(%d%d%d%d%d%d%d%d%d%d)$" or "0000000000"
    return setmetatable({ number = n, __index = self }, self)
end
"^1?(%d%d%d%d%d%d%d%d%d%d)$"
return setmetatable({ number = tonumber(n), __index = self }, self)
function PhoneNumber:areaCode()  -- what was symbol parameter for?
    return math.floor( self.number / 10^7 )
end

Context

StackExchange Code Review Q#70633, answer score: 4

Revisions (0)

No revisions yet.