Skip to content

Commit

Permalink
refactor: isValid is faster with lowercase
Browse files Browse the repository at this point in the history
  • Loading branch information
singuerinc committed May 29, 2018
1 parent 86669ee commit f7ca2b0
Show file tree
Hide file tree
Showing 19 changed files with 106 additions and 83 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ isNIF('06672804K'); //=> true
// checks if it is a valid NIE
isNIE('X1302311M'); //=> true

// returns the control letter in lower case
ctrlChar('X1302311M'); //=> 'm'
ctrlChar('X1302311'); //=> 'm'
// returns the control letter in upper case
ctrlChar('X1302311M'); //=> 'M'
ctrlChar('X1302311'); //=> 'M'
```

### Generators
Expand Down
6 changes: 3 additions & 3 deletions benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ benches.push(
}),
new Benchmark.Suite('ctrl char')
.add('better-dni#ctrlChar', () => {
better_dni_isValid_ctrlChar('X3825208');
better_dni_isValid_ctrlChar('X0729124R');
})
.add('dni-js-validator#getControlDigit', () => {
dni_js_getControlDigit('X3825208');
dni_js_getControlDigit('X0729124R');
})
.on('cycle', function(event) {
console.log(String(event.target));
Expand Down Expand Up @@ -74,7 +74,7 @@ benches.push(
})
);

Benchmark.invoke([...benches], {
Benchmark.invoke([benches[0]], {
name: 'run',
args: true,
queued: true
Expand Down
75 changes: 40 additions & 35 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Better DNI v1.12.0
// Better DNI v2.0.0
// https://github.com/singuerinc/better-dni
// (c) 2017-2018 Nahuel Scotti
// Better DNI may be freely distributed under the MIT license.
Expand All @@ -9,9 +9,30 @@
(factory((global.betterDni = {})));
}(this, (function (exports) { 'use strict';

const _isNIE = v => /^[XYZ]{1}[0-9]{7}[trwagmyfpdxbnjzsqvhlcke]{1}$/i.test(v);
const _isNIE = v => /^[XYZ]{1}[0-9]{7}[TRWAGMYFPDXBNJZSQVHLCKE]{1}$/i.test(v);

const _isNIF = v => /^[0-9]{8}[trwagmyfpdxbnjzsqvhlcke]{1}$/i.test(v);
const _isNIF = v => /^[0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKE]{1}$/i.test(v);

/**
* Returns true if the string is a valid DNI (NIF or NIE)
* @param {string} value
* @returns {boolean}
* @since 1.1.0
* @example
* isValid("X9464186P"); // => true
* isValid("03118880B"); // => true
*/
const isValid = value => {
const dni = (!value ? '' : value).toLowerCase(); // lowercase is faster

if (dni.length !== 9 && !_isNIE(dni) && !_isNIF(dni)) return false;

const f = { x: '0', y: '1', z: '2' }[dni[0]] || dni[0];
const dni_1_to_7 = dni.substr(1, 7);
const i = +(f + dni_1_to_7) % 23;

return 'trwagmyfpdxbnjzsqvhlcket'[i] === dni[8];
};

function _Random(seed) {
this._seed = seed % 2147483647;
Expand All @@ -24,49 +45,36 @@

// _Random :: https://gist.github.com/blixt/f17b47c62508be59987b#file-prng-js

const LETTERS = 'TRWAGMYFPDXBNJZSQVHLCKE';

const _idxOf = x => y => x.indexOf(y);
const _headAsNum = _idxOf('XYZ');
const _lastIndex = _idxOf('TRWAGMYFPDXBNJZSQVHLCKE');
const _lastIndex = _idxOf(LETTERS);
const _upper = x => x.toUpperCase();

const _letter = x => 'trwagmyfpdxbnjzsqvhlcke'[+x % 23];
const _letter = x => LETTERS[+x % 23];
const _randStrLimit = limit => ('' + Math.random()).substr(-limit);
const _randFloat = seed => (new _Random(seed).next() - 1) / 2147483646;

const _char = y => {
const f = { x: '0', y: '1', z: '2' }[y[0]] || y[0];
const f = { X: '0', Y: '1', Z: '2' }[y[0]] || y[0];
const i = f + '' + y.substr(1, 7);
return _letter(i);
};

/**
* Returns true if the string is a valid DNI (NIF or NIE)
* @param {string} value
* @returns {boolean}
* @since 1.1.0
* @example
* isValid("X9464186P"); // => true
* isValid("03118880B"); // => true
*/
const isValid = value => {
const dni = (!value ? '' : value).toLowerCase();
if (dni.length !== 9 && !_isNIE(dni) && !_isNIF(dni)) return false;
return _char(dni) === dni[8];
};

/**
* Returns the control letter in lower case
* Returns the control letter in upper case
* for a NIF or NIE with or without control letter
* @param {string} value
* @returns {string}
* @since 1.9.1
* @example
* ctrlChar("X9464186P"); // => 'p'
* ctrlChar("X9464186"); // => 'p'
* ctrlChar("03118880B"); // => 'b'
* ctrlChar("03118880"); // => 'b'
* ctrlChar("X9464186P"); // => 'P'
* ctrlChar("X9464186"); // => 'P'
* ctrlChar("03118880B"); // => 'B'
* ctrlChar("03118880"); // => 'B'
*/
const ctrlChar = x => _char(x.toLowerCase());
const ctrlChar = x => _char(x.toUpperCase());

/**
* Returns true if the string is a NIE
Expand All @@ -77,9 +85,7 @@
* isNIE("X4108613P"); // => true
*/
const isNIE = value => {
return (
!!value && value.length === 9 && _isNIE(value) && ctrlChar(value) === value[8].toLowerCase()
);
return !!value && value.length === 9 && _isNIE(value) && ctrlChar(value) === _upper(value[8]);
};

/**
Expand All @@ -91,9 +97,7 @@
* isNIF("93375221M"); // => true
*/
const isNIF = value => {
return (
!!value && value.length === 9 && _isNIF(value) && ctrlChar(value) === value[8].toLowerCase()
);
return !!value && value.length === 9 && _isNIF(value) && ctrlChar(value) === _upper(value[8]);
};

/**
Expand Down Expand Up @@ -184,8 +188,9 @@

// random nie
const num = Math.floor(1000000 * headOne + (9999999 - 1000000 * headOne - 23) * _randFloat(seed));
const rest = +(headNum + '' + num) % 23;
const h = +(headNum + '' + num) - rest + lastNum;
const b = +(headNum + '' + num);
const rest = b % 23;
const h = b - rest + lastNum;

const s = '0' + h + last;
const a = s.substr(-9);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "better-dni",
"version": "1.12.0",
"version": "2.0.0",
"description": "The fastest Spanish DNI (NIE / NIF) validation",
"main": "dist/index.js",
"license": "MIT",
Expand Down
12 changes: 6 additions & 6 deletions src/ctrlChar.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { _char } from './internal/_char';

/**
* Returns the control letter in lower case
* Returns the control letter in upper case
* for a NIF or NIE with or without control letter
* @param {string} value
* @returns {string}
* @since 1.9.1
* @example
* ctrlChar("X9464186P"); // => 'p'
* ctrlChar("X9464186"); // => 'p'
* ctrlChar("03118880B"); // => 'b'
* ctrlChar("03118880"); // => 'b'
* ctrlChar("X9464186P"); // => 'P'
* ctrlChar("X9464186"); // => 'P'
* ctrlChar("03118880B"); // => 'B'
* ctrlChar("03118880"); // => 'B'
*/
const ctrlChar = x => _char(x.toLowerCase());
const ctrlChar = x => _char(x.toUpperCase());

export { ctrlChar };
2 changes: 1 addition & 1 deletion src/internal/_char.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { _letter } from './_utils';

const _char = y => {
const f = { x: '0', y: '1', z: '2' }[y[0]] || y[0];
const f = { X: '0', Y: '1', Z: '2' }[y[0]] || y[0];
const i = f + '' + y.substr(1, 7);
return _letter(i);
};
Expand Down
2 changes: 1 addition & 1 deletion src/internal/_isNIE.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const _isNIE = v => /^[XYZ]{1}[0-9]{7}[trwagmyfpdxbnjzsqvhlcke]{1}$/i.test(v);
export const _isNIE = v => /^[XYZ]{1}[0-9]{7}[TRWAGMYFPDXBNJZSQVHLCKE]{1}$/i.test(v);
2 changes: 1 addition & 1 deletion src/internal/_isNIF.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const _isNIF = v => /^[0-9]{8}[trwagmyfpdxbnjzsqvhlcke]{1}$/i.test(v);
export const _isNIF = v => /^[0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKE]{1}$/i.test(v);
6 changes: 4 additions & 2 deletions src/internal/_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ _Random.prototype.next = function() {

// _Random :: https://gist.github.com/blixt/f17b47c62508be59987b#file-prng-js

const LETTERS = 'TRWAGMYFPDXBNJZSQVHLCKE';

const _idxOf = x => y => x.indexOf(y);
const _headAsNum = _idxOf('XYZ');
const _lastIndex = _idxOf('TRWAGMYFPDXBNJZSQVHLCKE');
const _lastIndex = _idxOf(LETTERS);
const _upper = x => x.toUpperCase();

const _letter = x => 'trwagmyfpdxbnjzsqvhlcke'[+x % 23];
const _letter = x => LETTERS[+x % 23];
const _randStrLimit = limit => ('' + Math.random()).substr(-limit);
const _randFloat = seed => (new _Random(seed).next() - 1) / 2147483646;

Expand Down
5 changes: 2 additions & 3 deletions src/isNIE.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { _isNIE } from './internal/_isNIE';
import { _upper } from './internal/_utils';
import { ctrlChar } from './ctrlChar';

/**
Expand All @@ -10,9 +11,7 @@ import { ctrlChar } from './ctrlChar';
* isNIE("X4108613P"); // => true
*/
const isNIE = value => {
return (
!!value && value.length === 9 && _isNIE(value) && ctrlChar(value) === value[8].toLowerCase()
);
return !!value && value.length === 9 && _isNIE(value) && ctrlChar(value) === _upper(value[8]);
};

export { isNIE };
5 changes: 2 additions & 3 deletions src/isNIF.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { _isNIF } from './internal/_isNIF';
import { _upper } from './internal/_utils';
import { ctrlChar } from './ctrlChar';

/**
Expand All @@ -10,9 +11,7 @@ import { ctrlChar } from './ctrlChar';
* isNIF("93375221M"); // => true
*/
const isNIF = value => {
return (
!!value && value.length === 9 && _isNIF(value) && ctrlChar(value) === value[8].toLowerCase()
);
return !!value && value.length === 9 && _isNIF(value) && ctrlChar(value) === _upper(value[8]);
};

export { isNIF };
11 changes: 8 additions & 3 deletions src/isValid.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { _isNIE } from './internal/_isNIE';
import { _isNIF } from './internal/_isNIF';
import { _char } from './internal/_char';

/**
* Returns true if the string is a valid DNI (NIF or NIE)
Expand All @@ -12,9 +11,15 @@ import { _char } from './internal/_char';
* isValid("03118880B"); // => true
*/
const isValid = value => {
const dni = (!value ? '' : value).toLowerCase();
const dni = (!value ? '' : value).toLowerCase(); // lowercase is faster

if (dni.length !== 9 && !_isNIE(dni) && !_isNIF(dni)) return false;
return _char(dni) === dni[8];

const f = { x: '0', y: '1', z: '2' }[dni[0]] || dni[0];
const dni_1_to_7 = dni.substr(1, 7);
const i = +(f + dni_1_to_7) % 23;

return 'trwagmyfpdxbnjzsqvhlcket'[i] === dni[8];
};

export { isValid };
5 changes: 3 additions & 2 deletions src/randomNIEWith.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ const randomNIEWith = (xyz, l, seed = 100000000 * Math.random()) => {

// random nie
const num = Math.floor(1000000 * headOne + (9999999 - 1000000 * headOne - 23) * _randFloat(seed));
const rest = +(headNum + '' + num) % 23;
const h = +(headNum + '' + num) - rest + lastNum;
const b = +(headNum + '' + num);
const rest = b % 23;
const h = b - rest + lastNum;

const s = '0' + h + last;
const a = s.substr(-9);
Expand Down
18 changes: 9 additions & 9 deletions test/ctrlChar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ const assert = require('assert');
const { ctrlChar } = require('../dist/index');

describe('#ctrlChar', () => {
it('should return the letter for a NIE in lower case with control letter', () => {
assert.equal(ctrlChar('x9464186p'), 'p');
it('should return the letter for a NIE in upper case with control letter', () => {
assert.equal(ctrlChar('x9464186p'), 'P');
});

it('should return the letter for a NIE in upper case with control letter', () => {
assert.equal(ctrlChar('X9464186P'), 'p');
assert.equal(ctrlChar('X9464186P'), 'P');
});

it('should return the letter for a NIE in lower case without control letter', () => {
assert.equal(ctrlChar('x9464186'), 'p');
it('should return the letter for a NIE in upper case without control letter', () => {
assert.equal(ctrlChar('x9464186'), 'P');
});

it('should return the letter for a NIF in upper case without control letter', () => {
assert.equal(ctrlChar('X9464186'), 'p');
assert.equal(ctrlChar('X9464186'), 'P');
});

it('should return the letter for a NIF in lower case with control letter', () => {
assert.equal(ctrlChar('03118880b'), 'b');
it('should return the letter for a NIF in upper case with control letter', () => {
assert.equal(ctrlChar('03118880b'), 'B');
});

it('should return the letter for a NIF without control letter', () => {
assert.equal(ctrlChar('03118880'), 'b');
assert.equal(ctrlChar('03118880'), 'B');
});
});
8 changes: 7 additions & 1 deletion test/randomNIE.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
const assert = require('assert');
const { isNIE, randomNIE, isValid } = require('../dist/index');
const { isNIE, randomNIE, isValid, ctrlChar } = require('../dist/index');

describe('#randomNIE', () => {
it('should return a random nie', () => {
const nie = randomNIE();
assert.equal(isNIE(nie), true);
});

it('should return the ctrl char in upper case', () => {
const nie = randomNIE();
const char = ctrlChar(nie);
assert.equal(char, char.toUpperCase());
});

it('should create 20 valid items', () => {
const list = Array(20)
.fill(0)
Expand Down
8 changes: 4 additions & 4 deletions test/randomNIEWith.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ describe('#randomNIEWith', () => {

it('should generate a random NIE that ends with G', () => {
const nie = randomNIEWith('X', 'G');
assert.equal(ctrlChar(nie), 'g');
assert.equal(ctrlChar(nie), 'G');
});

it('should work with lower case', () => {
const nie = randomNIEWith('Y', 'g');
assert.equal(ctrlChar(nie), 'g');
const nie = randomNIEWith('y', 'g');
assert.equal(ctrlChar(nie), 'G');
});

it('should work with upper case', () => {
const nie = randomNIEWith('Z', 'C');
assert.equal(ctrlChar(nie), 'c');
assert.equal(ctrlChar(nie), 'C');
});

it('should not generate with invalid letters', () => {
Expand Down
Loading

0 comments on commit f7ca2b0

Please sign in to comment.