/*-------------------------------------------------------------------------------
  stringcompliance.ado: check list of strings for compliance with a rule set of regular expressions

    Copyright (C) 2016-2017  Daniel Bela (daniel.bela@lifbi.de)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

-------------------------------------------------------------------------------*/
*! version 1.1 10 May 2017 - updated messages issed when using option -verbose-
*! version 1.0 01 April 2016 - initial release
*! stringcompliance.ado: check variable names for compliance with a rule set of regular expressions
*! Daniel Bela (daniel.bela@lifbi.de), Leibniz-Institute for Educational Trajectories e.V. (LIfBi), Germany
program define stringcompliance , rclass
	// Stata version information: use unicode functions for string comparisons in Stata 14 and younger
	if (`c(stata_version)'>=14) {
		local regexm_fct ustrregexm
		version 14
	}
	else {
		local regexm_fct regexm
		version 11
	}
	syntax [anything(everything equalok name=stringlist id="list of test strings")] , RULEset(string asis) [verbose]
	// parse options
	if (missing(`"`stringlist'"')) unab stringlist : _all
	// start checking
	local unmatched `"`stringlist'"'
	foreach teststring of local stringlist {
		local rulenum 0
		foreach rule of local ruleset {
			local rule`++rulenum'expression `"`rule'"'
			if (`regexm_fct'(`"`teststring'"',`"`rule'"',0)) {
				local unmatched : list unmatched - teststring
				local rule`rulenum'matches : list rule`rulenum'matches | teststring
			}
		}
	}
	// return results
	return scalar rulecount=`rulenum'
	forvalues num=1/`rulenum' {
		return local rule`num'expression  `"`rule`num'expression'"'
		return local rule`num'matches `"`rule`num'matches'"'
		return scalar rule`num'matchcount=`: word count `rule`num'matches''
		if (`"`verbose'"'=="verbose" & !missing(`"`rule`num'matches'"')) {
			if (`: word count `rule`num'matches''>1) local plural s
			else local plural
			display as result in smcl `"test string`plural' compliant to rule {it:`num'} [i.e. "{it:`rule`num'expression'}"]: {it:`rule`num'matches'}"'
		}
	}
	return local unmatched `"`unmatched'"'
	return scalar unmatchedcount=`: word count `unmatched''
	if (`"`verbose'"'=="verbose" & !missing(`"`unmatched'"')) {
		if (`: word count `unmatched''>1) local plural s
		else local plural
		display as result in smcl `"test string`plural' {bf:not} compliant to any rule: {it:`unmatched'}"'
	}
	exit 0
end
// EOF