Skip to content

Instantly share code, notes, and snippets.

@bodia-uz
Created January 22, 2015 23:42
Show Gist options
  • Save bodia-uz/eabef29d40ea83cb8c00 to your computer and use it in GitHub Desktop.
Save bodia-uz/eabef29d40ea83cb8c00 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<script id="jsbin-javascript">
function TextPattern(pattern){
this.opener = '{';
this.closer = '}';
this.delimiter = '|';
this.parse(pattern);
}
TextPattern.prototype = (function() {
var META_CHAR_PATTERN = /[-[\]{}()*+?.\\^$|,]/g;
var MARKUP_PATTERN = /{([^}]+)}/g;
var tmp = {};
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function sample(phrase, delimiter) {
var variants = phrase.split(delimiter);
var tries = variants.length;
var maxIndex = variants.length - 1;
var randomIndex = random(0, maxIndex);
// find not taken variant
while (tmp[phrase] && tmp[phrase][randomIndex] && tries--) {
randomIndex = randomIndex < maxIndex ? randomIndex + 1 : 0;
}
// if all variants taken,
// reset taken variants
// else save value as new one variant
tmp[phrase] = !tries ? {} : tmp[phrase] || {};
tmp[phrase][randomIndex] = true;
return variants[randomIndex];
}
function escape(string) {
return string.replace(META_CHAR_PATTERN, "\\$&");
}
function wrap(string, opener, closer) {
return opener + string + closer;
}
function parse(string, opener, closer) {
/* Use an optimized regex when opener and closer are one character each */
var iterator = new RegExp(escape(opener) + '|' + escape(closer), 'g');
var results = [];
var openTokens;
var matchStartIndex;
var match;
do {
openTokens = 0;
while (match = iterator.exec(string)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(string.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
}
function getGroups(pattern, opener, closer) {
var matches = parse(pattern, opener, closer);
return matches.map(function(match) {
var groups = getGroups(match, opener, closer)
return {
phrase: match,
groups: groups,
hasGroups: !!groups.length,
marker: function(phrase) {
return wrap(phrase || this.phrase, opener, closer);
}
};
});
}
function render(pattern, groups, delimiter) {
var result = pattern;
//console.log(phrases);
groups.forEach(function(group) {
var phrase = !group.hasGroups ? group.phrase : render(group.phrase, group.groups, delimiter);
var marker = group.marker(phrase);
if (group.hasGroups) {
result = result.replace(group.phrase, phrase);
}
result = result.replace(marker, sample(phrase, delimiter));
});
return result;
}
return {
parse: function(pattern) {
var self = this;
this.pattern = pattern;
this.groups = getGroups(pattern, this.opener, this.closer, this.delimiter);
},
render: function() {
return render(this.pattern, this.groups, this.delimiter);
}
};
})();
var text = 'hello {world|bodia|zhup|{some|no|any}body}! Let\'s {go|play|cry|eat|sleep|do something}{!|?}';
var pattern = new TextPattern(text);
console.log(pattern.render());
console.log(pattern.render());
console.log(pattern.render());
</script>
<script id="jsbin-source-javascript" type="text/javascript">function TextPattern(pattern){
this.opener = '{';
this.closer = '}';
this.delimiter = '|';
this.parse(pattern);
}
TextPattern.prototype = (function() {
var META_CHAR_PATTERN = /[-[\]{}()*+?.\\^$|,]/g;
var MARKUP_PATTERN = /{([^}]+)}/g;
var tmp = {};
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function sample(phrase, delimiter) {
var variants = phrase.split(delimiter);
var tries = variants.length;
var maxIndex = variants.length - 1;
var randomIndex = random(0, maxIndex);
// find not taken variant
while (tmp[phrase] && tmp[phrase][randomIndex] && tries--) {
randomIndex = randomIndex < maxIndex ? randomIndex + 1 : 0;
}
// if all variants taken,
// reset taken variants
// else save value as new one variant
tmp[phrase] = !tries ? {} : tmp[phrase] || {};
tmp[phrase][randomIndex] = true;
return variants[randomIndex];
}
function escape(string) {
return string.replace(META_CHAR_PATTERN, "\\$&");
}
function wrap(string, opener, closer) {
return opener + string + closer;
}
function parse(string, opener, closer) {
/* Use an optimized regex when opener and closer are one character each */
var iterator = new RegExp(escape(opener) + '|' + escape(closer), 'g');
var results = [];
var openTokens;
var matchStartIndex;
var match;
do {
openTokens = 0;
while (match = iterator.exec(string)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(string.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
}
function getGroups(pattern, opener, closer) {
var matches = parse(pattern, opener, closer);
return matches.map(function(match) {
var groups = getGroups(match, opener, closer)
return {
phrase: match,
groups: groups,
hasGroups: !!groups.length,
marker: function(phrase) {
return wrap(phrase || this.phrase, opener, closer);
}
};
});
}
function render(pattern, groups, delimiter) {
var result = pattern;
//console.log(phrases);
groups.forEach(function(group) {
var phrase = !group.hasGroups ? group.phrase : render(group.phrase, group.groups, delimiter);
var marker = group.marker(phrase);
if (group.hasGroups) {
result = result.replace(group.phrase, phrase);
}
result = result.replace(marker, sample(phrase, delimiter));
});
return result;
}
return {
parse: function(pattern) {
var self = this;
this.pattern = pattern;
this.groups = getGroups(pattern, this.opener, this.closer, this.delimiter);
},
render: function() {
return render(this.pattern, this.groups, this.delimiter);
}
};
})();
var text = 'hello {world|bodia|zhup|{some|no|any}body}! Let\'s {go|play|cry|eat|sleep|do something}{!|?}';
var pattern = new TextPattern(text);
console.log(pattern.render());
console.log(pattern.render());
console.log(pattern.render());</script></body>
</html>
function TextPattern(pattern){
this.opener = '{';
this.closer = '}';
this.delimiter = '|';
this.parse(pattern);
}
TextPattern.prototype = (function() {
var META_CHAR_PATTERN = /[-[\]{}()*+?.\\^$|,]/g;
var MARKUP_PATTERN = /{([^}]+)}/g;
var tmp = {};
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function sample(phrase, delimiter) {
var variants = phrase.split(delimiter);
var tries = variants.length;
var maxIndex = variants.length - 1;
var randomIndex = random(0, maxIndex);
// find not taken variant
while (tmp[phrase] && tmp[phrase][randomIndex] && tries--) {
randomIndex = randomIndex < maxIndex ? randomIndex + 1 : 0;
}
// if all variants taken,
// reset taken variants
// else save value as new one variant
tmp[phrase] = !tries ? {} : tmp[phrase] || {};
tmp[phrase][randomIndex] = true;
return variants[randomIndex];
}
function escape(string) {
return string.replace(META_CHAR_PATTERN, "\\$&");
}
function wrap(string, opener, closer) {
return opener + string + closer;
}
function parse(string, opener, closer) {
/* Use an optimized regex when opener and closer are one character each */
var iterator = new RegExp(escape(opener) + '|' + escape(closer), 'g');
var results = [];
var openTokens;
var matchStartIndex;
var match;
do {
openTokens = 0;
while (match = iterator.exec(string)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(string.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
}
function getGroups(pattern, opener, closer) {
var matches = parse(pattern, opener, closer);
return matches.map(function(match) {
var groups = getGroups(match, opener, closer)
return {
phrase: match,
groups: groups,
hasGroups: !!groups.length,
marker: function(phrase) {
return wrap(phrase || this.phrase, opener, closer);
}
};
});
}
function render(pattern, groups, delimiter) {
var result = pattern;
//console.log(phrases);
groups.forEach(function(group) {
var phrase = !group.hasGroups ? group.phrase : render(group.phrase, group.groups, delimiter);
var marker = group.marker(phrase);
if (group.hasGroups) {
result = result.replace(group.phrase, phrase);
}
result = result.replace(marker, sample(phrase, delimiter));
});
return result;
}
return {
parse: function(pattern) {
var self = this;
this.pattern = pattern;
this.groups = getGroups(pattern, this.opener, this.closer, this.delimiter);
},
render: function() {
return render(this.pattern, this.groups, this.delimiter);
}
};
})();
var text = 'hello {world|bodia|zhup|{some|no|any}body}! Let\'s {go|play|cry|eat|sleep|do something}{!|?}';
var pattern = new TextPattern(text);
console.log(pattern.render());
console.log(pattern.render());
console.log(pattern.render());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment