*! version 1.3.3 April 9, 2001 @ 13:49:43 program define icd9x version 6.0 /* 1.3.3 fixed bug in 'which' for proc codes */ /* 1.3.2 fixed the use of if or in */ /* 1.3.1 fixed a bug in the which option */ /* 1.3.0 upgraded to use version 6.0 of Stata */ /* 1.2.1 allows tagging with a given value... useful for making coded */ /* markers for multiple similar conditions */ /* 1.2.0 allows tagging by the first variable in which a code of interest */ /* appears (the which option) */ /* */ syntax [if] [in] [,Diagvar(str) Procvar(str) INDiag(str) EXDiag(str) INProc(str) EXProc(str) SUBset REPLACE Keep(str) Drop(str) NOCHECK UNSAFE WHICH KEEPVal(real 1) DROPVal(real 1)] if "`if'`in'"!="" { tempvar keeper mark `keeper' `if' `in' quietly count if `keeper' if r(N)==0 { display in red "Nothing to work with!" exit 2000 } local if "if `keeper'" local andkeep "& `keeper'" local orkeep "| `keeper'" } if "`diagvar'`procvar'"=="" { disp in red "You must use some variables!!!" exit 198 } if "`indiag'`exdiag'`inproc'`exproc'"=="" { disp in red "You must include or exclude some ICD-9 codes!" exit 198 } if "`diagvar'"=="" { if "`indiag'`exdiag'"!="" { disp in red "You cannot include or exclude diagnosis codes without any diagnosis variables!" exit 198 } } else { if "`indiag'`exdiag'"=="" { disp in red "You cannot specify diagnosis variables without any inclusions or exclusions!" exit 198 } unab diagvar : `diagvar', name(diagvars) confirm str5 var `diagvar' local indiag = upper("`indiag'") local exdiag = upper("`exdiag'") } if "`procvar'"=="" { if "`inproc'`exproc'"!="" { disp in red "You cannot include or exclude procedure codes without any procedure variables!" exit 198 } } else { if "`inproc'`exproc'"=="" { disp in red "You cannot specify procedure variables without any inclusions or exclusions!" exit 198 } unab procvar : `procvar', name(procvars) confirm str4 var `procvar' } if "`subset'"!="" { quietly d,s local dirty = r(changed) if "`replace'"=="" { if `dirty' { display in red "Trying to subset a changed file!" exit 4 } } if "`inproc'`indiag'"!="" { if "`keep'"=="" { tempvar keep gen byte `keep'=0 local notemp = "`keep' " } } if "`exproc'`exdiag'"!="" { if "`drop'"=="" { tempvar drop gen byte `drop'=0 local notemp = "`notemp' `drop'" } } } else { /* not subsetting data; just keeping marks */ local dirty 0 /* just don't care about it */ if "`inproc'`indiag'"!="" { if "`keep'"=="" { disp in red "If you do not take a subset, but you include, then you need a keep variable!" exit 198 } } if "`exproc'`exdiag'"!="" { if "`drop'"=="" { disp in red "If you do not take a subset, but you exclude, then you need a drop variable!" exit 198 } } } if `keepval'!=1 | `dropval'!=1 { if "`which'"!="" { disp in red "Which cannot be used in conjunction with either keepval or dropval!" exit 198 } if `keepval'==0 | `dropval'==0 { disp in red "Neither keepval nor dropval may be specified as 0!" exit 198 } } /* the following is needed so that the xxvarlists can be reparsed */ /* below.... they cannot be parsed and then assigned to a local */ /* macro because of the possibility of the local macro then being */ /* longer than 80 characters (damn the punch card!) */ if "`nocheck'"=="" { if "`indiag'"!="" { _ckicd9, codes(`indiag') type(m) } if "`exdiag'"!="" { _ckicd9, codes(`exdiag') type(m) } if "`inproc'"!="" { _ckicd9, codes(`inproc') type(p) } if "`exproc'"!="" { _ckicd9, codes(`exproc') type(p) } } local dirty = `dirty' & ("`unsafe'"=="") if `dirty' { preserve } capture { tempvar chars spec nums /* needed to keep varible generation low */ if "`diagvar'"!="" { tokenize "`diagvar'", parse(" ") local cnt 1 while "``cnt''"!="" { /* top of diag loop */ if "`exdiag'"!="" { if "`which'"!="" { local dropval "`cnt'" } _lbicd9 ``cnt'' `if', codes(`exdiag') type(m) mark(`drop') value(`dropval') chars(`chars') spec(`spec') nums(`nums') } if "`indiag'"!="" { if "`which'"!="" { local keepval "`cnt'" } _lbicd9 ``cnt'' `if', codes(`indiag') type(m) mark(`keep') value(`keepval') chars(`chars') spec(`spec') nums(`nums') } local cnt = `cnt' + 1 capture drop `chars' capture drop `spec' capture drop `nums' } /* end of diag loop */ } /* end ck for diagvars */ if "`procvar'"!="" { tokenize "`procvar'", parse(" ") local cnt 1 while "``cnt''"!="" { /* top of proc loop */ if "`exproc'"!="" { if "`which'"!="" { local dropval = 100+`cnt' } _lbicd9 ``cnt'' `if', codes(`exproc') type(p) mark(`drop') value(`dropval') chars(`chars') spec(`spec') nums(`nums') } if "`inproc'"!="" { if "`which'"!="" { local keepval = 100+`cnt' } _lbicd9 ``cnt'' `if', codes(`inproc') type(p) mark(`keep') value(`keepval') chars(`chars') spec(`spec') nums(`nums') } local cnt = `cnt' + 1 capture drop `chars' capture drop `spec' capture drop `nums' } /* end of proc loop */ } /* end ck for procvars */ } /* end capture block */ local rc = _rc if `rc' { if "`unsafe'"!="" { disp in yellow "Warning: data set not restored, since unsafe was specified!" display in yellow "Dataset name has been cleared..." global S_FN } } else { /* to hinder mistaken overwrites */ if "`subset'"!="" { /* check to see if save was specified */ mac def S_FN "" if "`keep'"!="" { keep if `keep' `andkeep' } if "`drop'"!="" { drop if `drop' `orkeep' } if _N==0 { disp in green "No cases fit your bill --- the data set will be cleared!" clear } } if `dirty' { restore, not } } error `rc' end /* version 1.0.0 February 12, 1993 */ /* version 1.1.0 Thursday, March 9, 2000 */ program define _ckicd9 syntax , Codes(str) Type(str) tokenize "`codes'", parse(" -") local cnt 1 while "``cnt''"!="" { _ck1icd9, code(``cnt'') type(`type') local next = `cnt' + 1 if "``next''"=="-" { /* have a range */ local next = `next' + 1 _ck1icd9, code(``next'') type(`type') /* now check the order */ if "`type'"=="p" { local start = ``cnt'' local end = ``next'' } else { if substr("``cnt''",1,1)>"9" { /* have an e- or v-code */ if substr("``cnt''",1,1)!=substr("``next''",1,1) { disp in red "A range cannot go across e/v codes: ``cnt'' - ``next''" exit 198 } local start = real(substr("``cnt''",2,.)) local end = real(substr("``next''",2,.)) } else { local start = ``cnt'' local end = ``next'' } } /* done getting start and end */ if `start'>=`end' { disp in red "Bad Range: ``cnt'' - ``next''" exit 198 } local cnt = `cnt' + 3 } else { /* just a singleton */ local cnt = `cnt' + 1 } } /* end of while loop */ end /* version 1.1.0 Thursday, March 9, 2000 */ /* version 1.0.0 February 12, 1993 */ program define _ck1icd9 syntax , Code(str) Type(str) if "`type'"!="m" & "`type'"!="p" { disp in red "The type must be m or p!" exit 198 } if substr("`code'",1,1)>"9" { /* have a char */ if "`type'"=="m" { /* medicals can have e- and v-codes */ if index("veVE",substr("`code'",1,1))==0 { disp in red "The only ICD-9 codes which start with letters are E- and V-codes!" disp in red "Bad Code: `code'" exit 198 } /* end v or e as starting char */ else { local ev = substr("`code'",1,1) local num = substr("`code'",2,.) _icd9rng, num(`num') type(m) ev(`ev') } } /* end type m check for chars */ else { /* have p type --- tsk tsk */ disp in red "There are no ICD-9 codes with letters for procedures!" disp in red "Bad Code: `code'" exit 198 } } /* end leading char check */ else { /* have leading number */ _icd9rng, num(`code') type(`type') } end /* version 1.1.0 Thursday, March 9, 2000 */ /* version 1.0.0 February 12, 1993 */ program define _icd9rng syntax, num(str) type(str) [ev(str)] local ev = lower("`ev'") /* just in case */ capture confirm num `num' if _rc { disp in red "Bad Code (letters in bad places?): `ev'`num'" exit 198 } if "`type'"=="p" { /* the easy stuff */ if `num'<0 | `num'>=100 { disp in red "ICD-9 Procedure Codes are between 0 and 99.99!" disp in red "Bad Code: `num'" exit 198 } } else { /* have an m code */ if "`ev'"=="" { /* straight code */ if `num'<0 | `num'>=1000 { disp in red "ICD-9 Medical Codes are between 0 and 999.9!" disp in red "Bad Code: `num'" exit 198 } } else { if "`ev'"=="e" { /* e code */ if `num'<0 | `num'>999 { disp in red "E-Codes are between 0 and 999!" disp in red "Bad Code: e`num'" exit 198 } } else { /* v code */ if `num'<0 | `num'>=83 { disp in red "V-Codes are between 0 and 82.9!" disp in red "Bad Code: v`num'" exit 198 } } } } end /* version 1.1.0 Thursday, March 9, 2000 */ program define _lbicd9 /* 1.1.0 switched to subprogram for version 6.0 of Stata */ /* 1.0.4 fixed problem with overwriting a var whose name is an extention */ /* of the intended name (e.g. marking tci overwriting tciold */ /* 1.0.3 fixed round-off problems when using ranges */ /* 1.0.2 fixed bug which tagged v and e codes for ranges of icd-9 codes */ /* which included codes of less than 100 */ syntax varname [if], Mark(str) Codes(str) Type(str) CHars(str) Spec(str) Nums(str) [Value(real 1)] /* since this is a helper --- most error checking is assumed done! */ if "`mark'"=="" { disp in red "_lbicd9 needs a variable for marking!" exit 198 } /* tempname val scalar `val'=`value' */ capture confirm new var `mark' if _rc ==0 { gen byte `mark'=0 `if' } capture confirm var `chars' if _rc { if "`type'"=="m" { local len 5 } else { local len 4 } gen str`len' `chars' = upper(`varlist') + substr("00000",1,`len'-length(`varlist')) } parse "`codes'", parse(" -") local cnt 1 while "``cnt''"!="" { local next = `cnt'+1 if "``next''"=="-" { local next = `next' + 1 if substr("``cnt''",1,1)>"9" { local code = substr("``cnt''",1,1) if "`code'"=="E" { local mult 10 } else { local mult 100 } local start = int(.5+`mult'*real(substr("``cnt''",2,.))) local end = int(.5+`mult'*real(substr("``next''",2,.))) } /* end fix for code */ else { /* normal icd-9's */ local start = int(.5+100*``cnt'') local end = int(.5+100*``next'') local code = "" } /* end start, end code assign */ capture confirm var `nums' if _rc { gen long `nums' = real(substr(`chars',1+(substr(`chars',1,1)>"9"),.)) } capture confirm var `spec' if _rc { gen str1 `spec' = upper(substr(`varlist',1,1)) replace `spec' = "" if `spec'<="9" } replace `mark' = `value' if (`spec'=="`code'") & (`nums' >=`start') & (`nums' <= `end') & `mark'==0 /* done, I think! */ local cnt = `cnt' + 3 } /* end of range stuff */ else { /* start of atomic stuff */ /* have to remove decimal point to make good char search */ local lcnt = index("``cnt''",".") if `lcnt' { local `cnt' = substr("``cnt''",1,`lcnt'-1) + substr("``cnt''",`lcnt'+1,.) } local lcnt = length("``cnt''") replace `mark' = `value' if substr(`chars',1,`lcnt')=="``cnt''" & `mark'==0 local cnt = `cnt' + 1 } } end