Skip to content

Instantly share code, notes, and snippets.

@treelite
Created October 12, 2016 06:31
Show Gist options
  • Save treelite/951b2573574d7fe465ce4127f9ee8d63 to your computer and use it in GitHub Desktop.
Save treelite/951b2573574d7fe465ce4127f9ee8d63 to your computer and use it in GitHub Desktop.
Validator for custom data
/**
* @file Validator for custom data
* @author treelite(c.xinle@gmail.com)
*/
const STATE_IDLE = 0;
const STATE_SPLIT = 1;
const STATE_TOKEN = 2;
const STATE_NEWLINE = 3;
class Validator {
constructor(str) {
this.str = str;
// current token
this.token = '';
// defined fields
this.fields = [];
// extraf fiels
this.extraFields = [];
// line count
this.lines = 0;
this.error = false;
// count of empty data
this.emptyValues = 0;
this.state = STATE_IDLE;
// all names
this.names = [];
// data for current line
this.values = [];
this.validate();
}
get fieldCount() {
return this.fields.length + this.extraFields.length;
}
getResult() {
if (this.error) {
return '0:0:0:format_error';
}
let lastFieldName = this.extraFields.length
? this.extraFields[this.extraFields.length - 1]
: this.fields[this.fields.length - 1];
return (this.lines - 1) + ':' + this.fieldCount + ':' + this.emptyValues + ':' + lastFieldName;
}
validate() {
let str = this.str;
let len = str.length;
let c;
let steps;
let i = 0;
while (i < len) {
steps = 1;
c = str.charAt(i);
if (c === '|') {
steps = this.split();
}
else if (c === '~') {
steps = this.escape(c + str.charAt(i + 1));
}
else {
steps = this.eatToken(c);
}
if (this.error) {
break;
}
i += steps;
}
}
eatToken(c) {
if (this.state === STATE_TOKEN || this.state === STATE_SPLIT) {
this.state = STATE_TOKEN;
this.token += c;
}
else {
this.error = true;
}
return 1;
}
checkName(name) {
return name && (this.names.indexOf(name) < 0);
}
split() {
if (this.state === STATE_TOKEN || this.state === STATE_SPLIT) {
// collect name
if (this.values.length === 0 && !this.lines) {
if (this.checkName(this.token)) {
this.names.push(this.token);
}
else {
// name is empty
// or not unique
this.error = true;
}
}
this.values.push(this.token);
// handle empty value
if (!this.token) {
if (!this.lines) {
// field name can't be empty;
this.error = true;
}
else {
this.emptyValues++;
}
}
// handle extra fields
if (this.lines && this.values.length > this.fieldCount) {
this.extendField();
}
this.token = '';
}
this.state = STATE_SPLIT;
return 1;
}
extendField() {
let count = this.extraFields.length + 1;
let text = this.fields[this.fields.length - 1];
this.extraFields.push(text + '_' + count);
}
newLine() {
if (this.state !== STATE_SPLIT) {
this.error = true;
}
else {
this.state = STATE_NEWLINE;
if (!this.lines) {
this.fields = this.values;
}
this.values = [];
this.lines++;
}
}
escape(token) {
let steps = 1;
if (token === '~n') {
this.newLine();
steps++;
}
else if (token === '~|' || token === '~~') {
this.eatToken(token.charAt(1));
steps++;
}
else {
this.eatToken(token.charAt(0));
}
return steps;
}
}
function validate(str) {
let validator = new Validator(str);
return validator.getResult();
}
console.log(validate('~~~'));
console.log(validate('|name|addr~~ness|~n|Patrick|partick@test.com|pat@test.com|~n|Annie||annie@test.com|~n'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment