TMGSTUTL ;TMG/kst/String Utilities and Library ;03/25/06,5/10/10 ; 5/19/10 5:01pm
;;1.0;TMG-LIB;**1**;09/01/05
;"TMG STRING UTILITIES
;"=======================================================================
;" API -- Public Functions.
;"=======================================================================
;"CleaveToArray^TMGSTUTL(Text,Divider,Array)
;"CatArray(Words,i1,i2,DivChr) -- return concat array from index1 to index2
;"CleaveStr^TMGSTUTL(Text,Divider,PartB)
;"SplitStr^TMGSTUTL(Text,Width,PartB)
;"SetStrLen^TMGSTUTL(Text,Width)
;"$$NestSplit^TMGSTUTL(Text,OpenBracket,CloseBracket,SBefore,S,SAfter)
;"$$Substitute^TMGSTUTL(S,Match,NewValue)
;"$$FormatArray^TMGSTUTL(InArray,OutArray,Divider)
;"$$Trim^TMGSTUTL(S,TrimCh) ; --> or use $$TRIM^XLFSTR
;"$$TrimL^TMGSTUTL(S,TrimCh)
;"$$TrimR^TMGSTUTL(S,TrimCh)
;"$$TrimRType^TMGSTUTL(S,type)
;"$$NumLWS^TMGSTUTL(S)
;"$$MakeWS^TMGSTUTL(n)
;"WordWrapArray^TMGSTUTL(.Array,Width,SpecialIndent)
;"SplitLine^TMGSTUTL(s,.LineArray,Width)
;"WriteWP^TMGSTUTL(NodeRef)
;"$$LPad^TMGSTUTL(S,width) ;"NOTE: should use XLFSTR fn below
;"$$RPad^TMGSTUTL(S,width) ;"NOTE: should use XLFSTR fn below
;"$$Center^TMGSTUTL(S,width) ;"NOTE: should use XLFSTR fn below
;"$$Clip^TMGSTUTL(S,width)
;"$$STRB2H^TMGSTUTL(s,F) Convert a string to hex characters
;"$$CapWords^TMGSTUTL(S,Divider) ;"capitalize the first character of each word in a string
;"$$LinuxStr^TMGSTUTL(S) ;"Convert string to a valid linux filename
;"StrToWP^TMGSTUTL(s,pArray,width,DivCh,InitLine) ;"wrap long string into a WP array
;"$$WPToStr^TMGSTUTL(pArray,DivCh,MaxLen,InitLine)
;"Comp2Strs(s1,s2) -- compare two strings and assign an arbritrary score to their similarity
;"$$PosNum(s,[Num],LeadingSpace) -- return position of a number in a string
;"IsNumeric(s) -- deterimine if word s is a numeric
;"ScrubNumeric(s) -- remove numeric words from a sentence
;"Pos(subStr,s,count) -- return the beginning position of subStr in s
;"DiffPos(s1,s2) -- Return the position of the first difference between s1 and s2
;"DiffWords(Words1,Words2) -- Return index of first different word between Words arrays
;"SimStr(s1,p1,s2,p2) -- return matching string in s1 and s2, starting at position p1,p2
;"SimWord(Words1,p1,Words2,p2) -- return the matching words in both words array 1 and 2, starting
;" at word positions p1 and p2.
;"SimPos(s1,s2) -- return the first position that two strings are similar.
;"SimWPos(Words1,Words2,DivStr,p1,p2,MatchStr) -- return the first position that two word arrays
;" are similar. This means the first index in Words array 1 that matches to words in Words array 2.
;"DiffStr(s1,s2,DivChr) -- Return how s1 differs from s2.
;"CatArray(Words,i1,i2,DivChr) -- return concat array from index1 to index2
;"$$QtProtect(s) -- Protects quotes by converting all quotes to double quotes (" --> "")
;"$$QTPROTECT(S) -- Same as $$QtProtect(s)
;"$$InQt(s,Pos) -- return if a character at position P is inside quotes in s
;"$$HNQTSUB(s,SubStr) --Same as $$HasNonQtSub
;"$$HasNonQtSub(s,SubStr) -- return if string s contains SubStr, but not inside quotes.
;"$$GetWord(s,Pos,OpenDiv,CloseDiv) -- extract a word from a sentance, bounded by OpenDiv,CloseDiv
;"$$MATCHXTR(s,DivCh,Group,Map) -- Same as $$MatchXtract
;"$$MatchXtract(s,DivCh,Group,Map) -- extract a string bounded by DivCh, honoring matching encapsulators
;"MapMatch(s,Map) -- map a string with nested braces, parentheses etc (encapsulators)
;"$$CmdChStrip(s) -- Strips all characters < #32 from string.
;"$$StrBounds(s,p) -- return position of end of string
;"NonWhite(s,p) -- return index of first non-whitespace character
;"Pad2Pos(Pos,ch) -- return a padding string from current $X up to Pos, using ch
;"HTML2TXT(Array) -- Take WP array that is HTML formatted, and strip
, and return in a format of 1 line per array node.
;"TrimTags(lineS) -- cut out HTML tags (e.g. <...>) from lineS, however, is protected
;"$$IsHTML(IEN8925) --specify if the text held in the REPORT TEXT field in record IEN8925 is HTML markup
;"=======================================================================
;"Dependancies
;" uses TMGDEBUG for debug messaging.
;"=======================================================================
;"=======================================================================
;"------------------------------------------------------------------------
;"FYI, String functions in XLFSTR module:
;"------------------------------------------------------------------------
;"$$CJ^XLFSTR(s,i[,p]) -- Returns a center-justified string
;" s=string, i=field size, p(optional)=pad character
;"$$LJ^XLFSTR(s,i[,p]) -- Returns a left-justified string
;" s=string, i=field size, p(optional)=pad character
;"$$RJ^XLFSTR(s,i[,p]) -- Returns a right-justified string
;" s=string, i=field size, p(optional)=pad character
;"$$INVERT^XLFSTR(s) -- returns an inverted string (i.e. "ABC"-->"CBA")
;"$$LOW^XLFSTR(s) -- returns string with all letters converted to lower-case
;"$$UP^XLFSTR(s) -- returns string with all letters converted to upper-case
;"$$TRIM^XLFSTR(s,[LRFlags],[char])
;"$$REPEAT^XLFSTR(s,Count) -- returns a string that is a repeat of s Count times
;"$$REPLACE^XLFSTR(s,.spec) -- Uses a multi-character $TRanslate to return a
;" string with the specified string replaced
;" s=input string, spec=array passed by reference
;" spec format:
;" spec("Any_Search_String")="Replacement_String"
;"$$STRIP^XLFSTR(s,Char) -- returns string striped of all instances of Char
;"=======================================================================
CleaveToArray(Text,Divider,Array,InitIndex)
;"Purpose: To take a string, delineated by 'divider' and
;" to split it up into all its parts, putting each part
;" into an array. e.g.:
;" This/Is/A/Test, with '/' divider would result in
;" Array(1)="This"
;" Array(2)="Is"
;" Array(3)="A"
;" Array(4)="Test"
;" Array(cMaxNode)=4 ;cMaxNode="MAXNODE"
;"Input: Text - the input string -- should NOT be passed by reference.
;" Divider - the delineating string
;" Array - The array to receive output **SHOULD BE PASSED BY REFERENCE.
;" InitIndex - OPTIONAL -- The index of the array to start with, i.e. 0 or 1. Default=1
;"Output: Array is changed, as outlined above
;"Result: none
;"Notes: Note -- Text is NOT changed (unless passed by reference, in
;" which case the next to the last piece is put into Text)
;" Array is killed, the filled with data **ONLY** IF DIVISIONS FOUND
;" Limit of 256 nodes
;" if cMaxNode is not defined, "MAXNODE" will be used
set DBIndent=$get(DBIndent,0)
do DebugEntry^TMGDEBUG(.DBIndent,"CleaveToArray")
set InitIndex=$get(InitIndex,1)
new PartB
new count set count=InitIndex
set cMaxNode=$get(cMaxNode,"MAXNODE")
kill Array ;"Clear out any old data
C2ArLoop
if '(Text[Divider) do goto C2ArDone
. set Array(count)=Text ;"put it all into first line.
. set Array(cMaxNode)=1
do CleaveStr(.Text,Divider,.PartB)
set Array(count)=Text
set Array(cMaxNode)=count
set count=count+1
if '(PartB[Divider) do goto C2ArDone
. set Array(count)=PartB
. set Array(cMaxNode)=count
else do goto C2ArLoop
. set Text=$get(PartB)
. set PartB=""
C2ArDone
do DebugExit^TMGDEBUG(.DBIndent,"CleaveToArray")
quit
CleaveStr(Text,Divider,PartB)
;"Purpse: To take a string, delineated by 'Divider'
;" and to split it into two parts: Text and PartB
;" e.g. Text="Hello\nThere"
;" Divider="\n"
;" Function will result in: Text="Hello", PartB="There"
;"Input: Text - the input string **SHOULD BE PASSED BY REFERENCE.
;" Divider - the delineating string
;" PartB - the string to get second part **SHOULD BE PASSED BY REFERENCE.
;"Output: Text and PartB will be changed
;" Function will result in: Text="Hello", PartB="There"
;"Result: none
set DBIndent=$get(DBIndent,0)
do DebugEntry^TMGDEBUG(.DBIndent,"CleaveStr")
do DebugMsg^TMGDEBUG(DBIndent,"Text=",Text)
if '$data(Text) goto CSDone
if '$Data(Divider) goto CSDone
set PartB=""
new PartA
if Text[Divider do
. set PartA=$piece(Text,Divider,1)
. set PartB=$piece(Text,Divider,2,256)
. set Text=PartA
do DebugMsg^TMGDEBUG(DBIndent,"After Processing, Text='",Text,"', and PartB='",PartB,"'")
CSDone
do DebugExit^TMGDEBUG(.DBIndent,"CleaveStr")
quit
SplitStr(Text,Width,PartB)
;"PUBLIC FUNCTION
;"Purpose: To a string into two parts. The first part will fit within 'Width'
;" the second part is what is left over
;" The split will be inteligent, so words are not divided (splits at a space)
;"Input: Text = input text. **Should be passed by reference
;" Width = the constraining width
;" PartB = the left over part. **Should be passed by reference
;"output: Text and PartB are modified
;"result: none.
new Len
set Width=$get(Width,80)
new SpaceFound set SpaceFound=0
new SplitPoint set SplitPoint=Width
set Text=$get(Text)
set PartB=""
set Len=$length(Text)
if Len>Width do
. new Ch
. for SplitPoint=SplitPoint:-1:1 do quit:SpaceFound
. . set Ch=$extract(Text,SplitPoint,SplitPoint)
. . set SpaceFound=(Ch=" ")
. if 'SpaceFound set SplitPoint=Width
. set s1=$extract(Text,1,SplitPoint)
. set PartB=$extract(Text,SplitPoint+1,1024) ;"max String length=1024
. set Text=s1
else do
quit
SetStrLen(Text,Width)
;"PUBLIC FUNCTION
;"Purpose: To make string exactly Width in length
;" Shorten as needed, or pad with terminal spaces as needed.
;"Input: Text -- should be passed as reference. This is string to alter.
;" Width -- the desired width
;"Results: none.
set Text=$get(Text)
set Width=$get(Width,80)
new result set result=Text
new i,Len
set Len=$length(result)
if Len>Width do
. set result=$extract(result,1,Width)
else if Len "ABC$$$DEF"
;" Substitute("ABC###DEF","###","$") --> "ABC$DEF"
;"Result: returns altered string (if any alterations indicated)
;"Output: S is altered, if passed by reference.
new spec
set spec($get(Match))=$get(NewValue)
set S=$$REPLACE^XLFSTR(S,.spec)
quit S
FormatArray(InArray,OutArray,Divider)
;"PUBLIC FUNCTION
;"Purpose: The XML parser does not recognize whitespace, or end-of-line
;" characters. Thus many lines get lumped together. However, if there
;" is a significant amount of text, then the parser will put the text into
;" several lines (when get attrib text called etc.)
;" SO, this function is to take an array composed of input lines (each
;" with multiple sublines clumped together), and format it such that each
;" line is separated in the array.
;" e.g. Take this input array"
;" InArray(cText,1)="line one\nline two\nline three\n
;" InArray(cText,2)="line four\nline five\nline six\n
;" and convert to:
;" OutArray(1)="line one"
;" OutArray(2)="line two"
;" OutArray(3)="line three"
;" OutArray(4)="line four"
;" OutArray(5)="line five"
;" OutArray(6)="line six"
;"Input: InArray, best if passed by reference (faster) -- see example above
;" Note: expected to be in format: InArray(cText,n)
;" OutArray, must be passed by reference-- see example above
;" Divider: the character(s) that divides lines ("\n" in this example)
;"Note: It is expected that InArray will be index by integers (i.e. 1, 2, 3)
;" And this should be the case, as that is how XML functions pass back.
;" Limit of 256 separate lines on any one InArray line
;"Output: OutArray is set, any prior data is killed
;"result: 1=OK to continue, 0=abort
set DEBUG=$get(DEBUG,0)
set cOKToCont=$get(cOKToCont,1)
set cAbort=$get(cAbort,0)
if DEBUG>0 do DebugEntry^TMGDEBUG(.DBIndent,"FormatArray")
new result set result=cOKToCont
new InIndex
new OutIndex set OutIndex=1
new TempArray
new Done
kill OutArray ;"remove any prior data
if DEBUG>0 do DebugMsg^TMGDEBUG(DBIndent,"Input array:")
if DEBUG do ArrayDump^TMGDEBUG("InArray")
if $data(Divider)=0 do goto FADone
. set result=cAbort
set Done=0
for InIndex=1:1 do quit:Done
. if $data(InArray(cText,InIndex))=0 set Done=1 quit
. if DEBUG>0 do DebugMsg^TMGDEBUG(DBIndent,"Converting line: ",InArray(cText,InIndex))
. do CleaveToArray^TMGSTUTL(InArray(cText,InIndex),Divider,.TempArray,OutIndex)
. if DEBUG>0 do DebugMsg^TMGDEBUG(DBIndent,"Resulting temp array:")
. if DEBUG do ArrayDump^TMGDEBUG("TempArray")
. set OutIndex=TempArray(cMaxNode)+1
. kill TempArray(cMaxNode)
. merge OutArray=TempArray
. if DEBUG>0 do DebugMsg^TMGDEBUG(DBIndent,"OutArray so far:")
. if DEBUG do ArrayDump^TMGDEBUG("OutArray")
FADone
if DEBUG>0 do DebugExit^TMGDEBUG(.DBIndent,"FormatArray")
quit result
TrimL(S,TrimCh)
;"Purpose: To a trip a string of leading white space
;" i.e. convert " hello" into "hello"
;"Input: S -- the string to convert. Won't be changed if passed by reference
;" TrimCh -- OPTIONAL: Charachter to trim. Default is " "
;"Results: returns modified string
;"Note: processing limitation is string length=1024
set DEBUG=$get(DEBUG,0)
set cOKToCont=$get(cOKToCont,1)
set cAbort=$get(cAbort,0)
set TrimCh=$get(TrimCh," ")
new result set result=$get(S)
new Ch set Ch=""
for do quit:(Ch'=TrimCh)
. set Ch=$extract(result,1,1)
. if Ch=TrimCh set result=$extract(result,2,1024)
quit result
TrimR(S,TrimCh)
;"Purpose: To a trip a string of trailing white space
;" i.e. convert "hello " into "hello"
;"Input: S -- the string to convert. Won't be changed if passed by reference
;" TrimCh -- OPTIONAL: Charachter to trim. Default is " "
;"Results: returns modified string
;"Note: processing limitation is string length=1024
set DEBUG=$get(DEBUG,0)
set cOKToCont=$get(cOKToCont,1)
set cAbort=$get(cAbort,0)
set TrimCh=$get(TrimCh," ")
if DEBUG>0 do DebugEntry^TMGDEBUG(.DBIndent,"TrimR")
new result set result=$get(S)
new Ch set Ch=""
new L
for do quit:(Ch'=TrimCh)
. set L=$length(result)
. set Ch=$extract(result,L,L)
. if Ch=TrimCh do
. . set result=$extract(result,1,L-1)
if DEBUG>0 do DebugExit^TMGDEBUG(.DBIndent,"TrimR")
quit result
Trim(S,TrimCh)
;"Purpose: To a trip a string of leading and trailing white space
;" i.e. convert " hello " into "hello"
;"Input: S -- the string to convert. Won't be changed if passed by reference
;" TrimCh -- OPTIONAL: Charachter to trim. Default is " "
;"Results: returns modified string
;"Note: processing limitation is string length=1024
;"NOTE: this function could be replaced with $$TRIM^XLFSTR
set DEBUG=$get(DEBUG,0)
set cOKToCont=$get(cOKToCont,1)
set cAbort=$get(cAbort,0)
set TrimCh=$get(TrimCh," ")
if DEBUG>0 do DebugEntry^TMGDEBUG(.DBIndent,"Trim")
new result set result=$get(S)
set result=$$TrimL(.result,TrimCh)
set result=$$TrimR(.result,TrimCh)
if DEBUG>0 do DebugExit^TMGDEBUG(.DBIndent,"Trim")
quit result
TrimRType(S,type)
;"Scope: PUBLIC FUNCTION
;"Purpose: trim characters on the right of the string of a specified type.
;" Goal, to be able to distinguish between numbers and strings.
;" i.e. "1234<=" --> "1234" by trimming strings
;"Input: S -- The string to work on
;" type -- the type of characters to TRIM: N for numbers,C for non-numbers (characters)
;"Results : modified string
set tempS=$get(S)
set type=$$UP^XLFSTR($get(type)) goto:(type="") TRTDone
new done set done=0
for quit:(tempS="")!done do
. new c set c=$extract(tempS,$length(tempS))
. new cType set cType="C"
. if +c=c set cType="N"
. if type["N" do
. . if cType="N" set tempS=$extract(tempS,1,$length(tempS)-1) quit
. . set done=1
. else if type["C" do
. . if cType="C" set tempS=$extract(tempS,1,$length(tempS)-1) quit
. . set done=1
. else set done=1
TRTDone quit tempS
NumLWS(S)
;"Scope: PUBLIC FUNCTION
;":Purpose: To count the number of white space characters on the left
;" side of the string
new result set result=0
new i,ch
set S=$get(S)
for i=1:1:$length(S) do quit:(ch'=" ")
. set ch=$extract(S,i,i)
. if ch=" " set result=result+1
quit result
MakeWS(n)
;"Scope: PUBLIC FUNCTION
;"Purpose: Return a whitespace string that is n characters long
new result set result=""
set n=$get(n,0)
if n'>0 goto MWSDone
new i
for i=1:1:n set result=result_" "
MWSDone
quit result
WordWrapArray(Array,Width,SpecialIndent)
;"Scope: PUBLIC FUNCTION
;"Purpose: To take an array and perform word wrapping such that
;" no line is longer than Width.
;" This function is really designed for reformatting a Fileman WP field
;"Input: Array MUST BE PASSED BY REFERENCE. This contains the array
;" to be reformatted. Changes will be made to this array.
;" It is expected that Array will be in this format:
;" Array(1)="Some text on the first line."
;" Array(2)="Some text on the second line."
;" Array(3)="Some text on the third line."
;" Array(4)="Some text on the fourth line."
;" or
;" Array(1,0)="Some text on the first line."
;" Array(2,0)="Some text on the second line."
;" Array(3,0)="Some text on the third line."
;" Array(4,0)="Some text on the fourth line."
;" Width -- the limit on the length of any line. Default value=70
;" SpecialIndent : if 1, then wrapping is done like this:
;" " This is a very long line......"
;" will be wrapped like this:
;" " This is a very
;" " long line ...
;" Notice that the leading space is copied subsequent line.
;" Also, a line like this:
;" " 1. Here is the beginning of a paragraph that is very long..."
;" will be wrapped like this:
;" " 1. Here is the beginning of a paragraph
;" " that is very long..."
;" Notice that a pattern '#. ' causes the wrapping to match the start of
;" of the text on the line above.
;" The exact rules for matching this are as follows:
;" (FirstWord?.N1".")!(FirstWord?1.3E1".")
;" i.e. any number of digits, followed by "."
;" OR 1-4 all upper-case characters followed by a "."
;" This will allow "VIII. " pattern but not "viii. "
;" HOWEVER, might get confused with a word, like "NOTE. "
;"
;" This, below, is not dependant on SpecialIndent setting
;" Also, because some of the lines have already partly wrapped, like this:
;" " 1. Here is the beginning of a paragraph that is very long..."
;" "and this is a line that has already wrapped.
;" So when the first line is wrapped, it would look like this:
;" " 1. Here is the beginning of a paragraph
;" " that is very long..."
;" "and this is a line that has already wrapped.
;" But is should look like this:
;" " 1. Here is the beginning of a paragraph
;" " that is very long...and this is a line
;" " that has already wrapped.
;" But the next line SHOULD NOT be pulled up if it is the start
;" of a new paragraph. I will tell by looking for #. paattern.
;"Result -- none
if $get(TMGDEBUG)>0 do DebugEntry^TMGDEBUG(.DBIndent,"WordWrapArray^TMGSTUTL")
new tempArray set tempArray="" ;"holds result during work.
new tindex set tindex=0
new index
set index=$order(Array(""))
new s
new residualS set residualS=""
new AddZero set AddZero=0
set Width=$get(Width,70)
if $get(TMGDEBUG)>0 do DebugMsg^TMGDEBUG(.DBIndent,"Starting loop")
if index'="" for do quit:((index="")&(residualS=""))
. set s=$get(Array(index))
. if s="" do
. . set s=$get(Array(index,0))
. . set AddZero=1
. if residualS'="" do ;"See if should join to next line. Don't if '#. ' pattern
. . new FirstWord set FirstWord=$piece($$Trim(s)," ",1)
. . if $get(TMGDEBUG)>0 do DebugMsg^TMGDEBUG(.DBIndent,"First Word: ",FirstWord)
. . if (FirstWord?.N1".")!(FirstWord?1.4U1".") do ;"match for '#.' pattern
. . . ;"Here we have the next line is a new paragraph, so don't link to residualS
. . . set tindex=tindex+1
. . . if AddZero=0 set tempArray(tindex)=residualS
. . . else set tempArray(tindex,0)=residualS
. . . set residualS=""
. if $length(residualS)+$length(s)'<256 do
. . if $get(TMGDEBUG)>0 do DebugMsg^TMGDEBUG(.DBIndent,"ERROR -- string too long.")
. set s=residualS_s
. set residualS=""
. if $length(s)>Width do
. . if $get(TMGDEBUG)>0 do DebugMsg^TMGDEBUG(.DBIndent,"Long line: ",s)
. . new LineArray
. . new NumLines
. . set NumLines=$$SplitLine(.s,.LineArray,Width,.SpecialIndent)
. . if $get(TMGDEBUG)>0 do ArrayDump^TMGDEBUG("LineArray")
. . set s=""
. . new LineIndex
. . for LineIndex=1:1:NumLines do
. . . set tindex=tindex+1
. . . if AddZero=0 set tempArray(tindex)=LineArray(LineIndex)
. . . else set tempArray(tindex,0)=LineArray(LineIndex)
. . ;"long wrap probably continues into next paragraph, so link together.
. . if NumLines>2 do
. . . if AddZero=0 set residualS=tempArray(tindex) set tempArray(tindex)=""
. . . else set residualS=tempArray(tindex,0) set tempArray(tindex,0)=""
. . . set tindex=tindex-1
. else do
. . set tindex=tindex+1
. . if AddZero=0 set tempArray(tindex)=s
. . else set tempArray(tindex,0)=s
. set index=$order(Array(index))
else do
. if $get(TMGDEBUG)>0 do DebugMsg^TMGDEBUG(.DBIndent,"Array appears empty")
kill Array
merge Array=tempArray
if $get(TMGDEBUG)>0 do ArrayDump^TMGDEBUG("Array")
if $get(TMGDEBUG)>0 do DebugExit^TMGDEBUG(.DBIndent," WordWrapArray^TMGSTUTL")
quit
SplitLine(s,LineArray,Width,SpecialIndent,Indent)
;"Scope: PUBLIC FUNCTION
;"Purpose: To take a long line, and wrap into an array, such that each
;" line is not longer than Width.
;" Line breaks will be made at spaces, unless there are no spaces in
;" the entire line (in which case, the line will be divided at Width).
;"Input: s= string with the long line. **If passed by reference**, then
;" it WILL BE CHANGED to equal the last line of array.
;" LineArray -- MUST BE PASSED BY REFERENCE. This OUT variable will
;" receive the resulting array.
;" Width = the desired wrap width.
;" SpecialIndent [OPTIONAL]: if 1, then wrapping is done like this:
;" " This is a very long line......"
;" will be wrapped like this:
;" " This is a very
;" " long line ...
;" Notice that the leading space is copied subsequent line.
;" Also, a line like this:
;" " 1. Here is the beginning of a paragraph that is very long..."
;" will be wrapped like this:
;" " 1. Here is the beginning of a paragraph
;" " that is very long..."
;" Notice that a pattern '#. ' causes the wrapping to match the start
;" of the text on the line above.
;" Indent [OPTIONAL]: Any absolute amount that all lines should be indented by.
;" This could be used if this long line is continuation of an
;" indentation above it.
;"Result: resulting number of lines (1 if no wrap needed).
if $get(TMGDEBUG)>0 do DebugEntry^TMGDEBUG(.DBIndent,"SplitLine")
new result set result=0
kill LineArray
if ($get(s)="")!($get(Width)'>0) goto SPDone
new index set index=0
new p,tempS,splitPoint
new PreSpace set PreSpace=$$NeededWS(s,.SpecialIndent,.Indent)
if ($length(s)>Width) for do quit:($length(s)'>Width)
. for splitPoint=1:1:Width do quit:($length(tempS)>Width)
. . set tempS=$piece(s," ",1,splitPoint)
. . ;"write "tempS>",tempS,!
. if splitPoint>1 do
. . set tempS=$piece(s," ",1,splitPoint-1)
. . set s=$piece(s," ",splitPoint,Width)
. else do
. . ;"We must have a word > Width with no spaces--so just divide
. . set tempS=$extract(s,1,Width)
. . set s=$extract(s,Width+1,999)
. set index=index+1
. set LineArray(index)=tempS
. set s=PreSpace_s
. ;"write "tempS>",tempS,!
. ;"write "s>",s,!
set index=index+1
set LineArray(index)=s
set result=index
SPDone
if $get(TMGDEBUG)>0 do DebugExit^TMGDEBUG(.DBIndent,"SplitLine")
quit result
NeededWS(S,SpecialIndent,Indent)
;"Scope: PRIVATE
;"Purpose: Evaluate the line, and create the white space string
;" need for wrapped lines
;"Input: s -- the string to eval. i.e.
;" " John is very happy today ... .. .. .. .."
;" or " 1. John is very happy today ... .. .. .. .."
;" SpecialIndent -- See SplitLine() discussion
;" Indent -- See SplitLine() discussion
new result set result=""
if $get(S)="" goto NdWSDone
new WSNum
set WSNum=+$get(Indent,0)
set WSNum=WSNum+$$NumLWS(S)
if $get(SpecialIndent)=1 do
. new ts,FirstWord
. set ts=$$TrimL(.S)
. set FirstWord=$piece(ts," ",1)
. if (FirstWord?.N1".")!(FirstWord?1.4U1".") do ;"match for '#.' pattern
. . set WSNum=WSNum+$length(FirstWord)
. . set ts=$piece(ts," ",2,9999)
. . set WSNum=WSNum+$$NumLWS(.ts)+1
set result=$$MakeWS(WSNum)
NdWSDone
quit result
WriteWP(NodeRef)
;"Purpose: Given a reference to a WP field, this function will print it out.
;"INput: NodeRef -- the name of the node to print out.
;" For example, "^PS(50.605,1,1)"
;"Modification: 2/10/06 -- I removed need for @NodeRef@(0) to contain data.
new i
;"if $get(@NodeRef@(0))="" goto WWPDone
set i=$order(@NodeRef@(0))
if i'="" for do quit:(i="")
. new OneLine
. set OneLine=$get(@NodeRef@(i))
. if OneLine="" set OneLine=$get(@NodeRef@(i,0))
. write OneLine,!
. set i=$order(@NodeRef@(i))
WWPDone quit
LPad(S,width)
;"Purpose: To add space ("pad") string S such that final width is per specified with.
;" space is added to left side of string
;"Input: S : the string to pad.
;" width : the desired final width
;"result: returns resulting string
;"Example: LPad("$5.23",7)=" $5.23"
quit $$RJ^XLFSTR(.S,.width," ")
RPad(S,width)
;"Purpose: To add space ("pad") string S such that final width is per specified with.
;" space is added to right side of string
;"Input: S : the string to pad.
;" width : the desired final width
;"result: returns resulting string
;"Example: RPad("$5.23",7)="$5.23 "
quit $$LJ^XLFSTR(.S,.width," ")
Center(S,width)
;"Purpose: to return a center justified string
quit $$CJ^XLFSTR(.S,.width," ")
Clip(S,width)
;"Purpose: to ensure that string S is no longer than width
new result set result=$get(S)
if result'="" set result=$extract(S,1,width)
ClipDone
quit result
STRB2H(s,F,noSpace)
;"Convert a string to hex characters)
;"Input: s -- the input string (need not be ascii characters)
;" F -- (optional) if F>0 then will append an ascii display of string.
;" noSpace -- (Optional) if >0 then characters NOT separated by spaces
;"result -- the converted string
new i,ch
new result set result=""
for i=1:1:$length(s) do
. set ch=$extract(s,i)
. set result=result_$$HEXCHR^TMGMISC($ascii(ch))
. if +$get(noSpace)=0 set result=result_" "
if $get(F)>0 set result=result_" "_$$HIDECTRLS^TMGSTUTL(s)
quit result
HIDECTRLS(s)
;"hide all unprintable characters from a string
new i,ch,byte
new result set result=""
for i=1:1:$length(s) do
. set ch=$e(s,i)
. set byte=$ascii(ch)
. if (byte<32)!(byte>122) set result=result_"."
. else set result=result_ch
quit result
CapWords(S,Divider)
;"Purpose: convert each word in the string: 'test string' --> 'Test String', 'TEST STRING' --> 'Test String'
;"Input: S -- the string to convert
;" Divider -- [OPTIONAL] the character used to separate string (default is ' ' [space])
;"Result: returns the converted string
new s2,part
new result set result=""
set Divider=$get(Divider," ")
set s2=$$LOW^XLFSTR(S)
for i=1:1 do quit:part=""
. set part=$piece(s2,Divider,i)
. if part="" quit
. set $extract(part,1)=$$UP^XLFSTR($extract(part,1))
. if result'="" set result=result_Divider
. set result=result_part
quit result
LinuxStr(S)
;"Purpose: convert string to a valid linux filename
;" e.g. 'File Name' --> 'File\ Name'
quit $$Substitute(.S," ","\ ")
NiceSplit(S,Len,s1,s2,s2Min,DivCh)
;"Purpose: to split S into two strings, s1 & s2
;" Furthermore, s1's length must be <= length.
;" and the split will be made at spaces
;"Input: S -- the string to split
;" Len -- the length limit of s1
;" s1 -- PASS BY REFERENCE, an OUT parameter
;" receives first part of split
;" s2 -- PASS BY REFERENCE, an OUT parameter
;" receives the rest of string
;" s2Min -- OPTIONAL -- the minimum that
;" length of s2 can be. Note, if s2
;" is "", then this is not applied
;" DivCH -- OPTIONAL, default is " ".
;" This is the character to split words by
;"Output: s1 and s2 is filled with data
;"Result: none
set (s1,s2)=""
if $get(DivCh)="" set DivCh=" "
if $length(S)'>Len do goto NSpDone
. set s1=S
new i
new done
for i=200:-1:1 do quit:(done)
. set s1=$piece(S,DivCh,1,i)_DivCh
. set s2=$piece(S,DivCh,i+1,999)
. set done=($length(s1)'>Len)
. if done,+$get(s2Min)>0 do
. . if s2="" quit
. . set done=($length(s2)'0)
. set OneLine=$get(@pArray@(i))
. if OneLine="" set OneLine=$get(@pArray@(i,0))
. if OneLine="" quit
. set Len=$length(result)+$length(DivCh)
. if Len+$length(OneLine)>MaxLen do
. . set OneLine=$extract(OneLine,1,(MaxLen-Len))
. set result=result_OneLine_DivCh
. set Len=Len+$length(OneLine)
. set i=$order(@pArray@(i))
quit result;
Comp2Strs(s1,s2)
;"Purpose: To compare two strings and assign an arbritrary score to their similarity
;"Input: s1,s2 -- The two strings to compare
;"Result: a score comparing the two strings
;" 0.5 point for every word in s1 that is also in s2 (case specific)
;" 0.25 point for every word in s1 that is also in s2 (not case specific)
;" 0.5 point for every word in s2 that is also in s1 (case specific)
;" 0.25 point for every word in s2 that is also in s1 (not case specific)
;" 1 points if same number of words in string (compared each way)
;" 2 points for each word that is in the same position in each string (case specific)
;" 1.5 points for each word that is in the same position in each string (not case specific)
new score set score=0
new Us1 set Us1=$$UP^XLFSTR(s1)
new Us2 set Us2=$$UP^XLFSTR(s2)
new i
for i=1:1:$length(s1," ") do
. if s2[$piece(s1," ",i) set score=score+0.5
. else if Us2[$piece(Us1," ",i) set score=score+0.25
. if $piece(s1," ",i)=$piece(s2," ",i) set score=score+1
. else if $piece(Us1," ",i)=$piece(Us2," ",i) set score=score+1.5
for i=1:1:$length(s2," ") do
. if s1[$piece(s2," ",i) set score=score+0.5
. else if Us1[$piece(Us2," ",i) set score=score+0.25
. if $piece(s1," ",i)=$piece(s2," ",i) set score=score+1
. else if $piece(Us1," ",i)=$piece(Us2," ",i) set score=score+1.5
if $length(s1," ")=$length(s2," ") set score=score+2
quit score
PosNum(s,Num,LeadingSpace)
;"Purpose: To return the position of the first Number in a string
;"Input: S -- string to check
;" Num -- OPTIONAL, default is 0-9 numbers. number to look for.
;" LeadingSpace -- OPTIONAL. If 1 then looks for " #" or " .#", not just "#"
;"Results: -1 if not found, otherwise position of found digit.
new result set result=-1
new Leader set Leader=""
if $get(LeadingSpace)=1 set Leader=" "
if $get(Num) do goto PNDone
. set result=$find(s,Leader_Num)-1
new temp,i,decimalFound
for i=0:1:9 do
. set decimalFound=0
. set temp=$find(s,Leader_i)
. if (temp=0)&(Leader'="") do
. . set temp=$find(s,Leader_"."_i)
. . if temp>-1 set decimalFound=1
. if temp>-1 set temp=temp-$length(Leader_i)
. if decimalFound set temp=temp-1
. if (temp>0)&((temp0)&(Leader=" ") set result=result+1
quit result
IsNumeric(s)
;"Purpose: To deterimine if word s is a numeric
;" Examples of numeric words:
;" 10, N-100, 0.5%, 50000UNT/ML
;" the test will be if the word contains any digit 0-9
;"Results: 1 if is a numeric word, 0 if not.
quit ($$PosNum(.s)>0)
ScrubNumeric(s)
;"Purpose: This is a specialty function designed to remove numeric words
;" from a sentence. E.g.
;" BELLADONNA ALK 0.3/PHENOBARB 16MG CHW TB --> BELLADONNA ALK /PHENOBARB CHW TB
;" ESTROGENS,CONJUGATED 2MG/ML INJ (IN OIL) --> ESTROGENS,CONJUGATED INJ (IN OIL)
new Array,i,result
set s=$$Substitute(s,"/MG","")
set s=$$Substitute(s,"/ML","")
set s=$$Substitute(s,"/"," / ")
set s=$$Substitute(s,"-"," - ")
do CleaveToArray(s," ",.Array)
new ToKill
set i=0 for set i=$order(Array(i)) quit:+i'>0 do
. if (Array(i)="MG")&($get(ToKill(i-1))=1) set ToKill(i)=1 quit
. if (Array(i)="MCG")&($get(ToKill(i-1))=1) set ToKill(i)=1 quit
. if (Array(i)="MEQ")&($get(ToKill(i-1))=1) set ToKill(i)=1 quit
. if (Array(i)="%")&($get(ToKill(i-1))=1) set ToKill(i)=1 quit
. if (Array(i)="MM")&($get(ToKill(i-1))=1) set ToKill(i)=1 quit
. if $$IsNumeric(Array(i))=0 quit
. set ToKill(i)=1
. new tempS set tempS=$get(Array(i-1))
. if (tempS="/")!(tempS="-") set ToKill(i-1)=1
. if (tempS="NO")!(tempS="#") set ToKill(i-1)=1
set i=0 for set i=$order(Array(i)) quit:+i'>0 do
. if $get(ToKill(i))=1 kill Array(i)
set i="",result=""
for set i=$order(Array(i)) quit:+i'>0 do
. set result=result_Array(i)_" "
set result=$$Trim(result)
set result=$$Substitute(result," / ","/")
set result=$$Substitute(result," - ","-")
quit result
Pos(subStr,s,count)
;"Purpose: return the beginning position of subStr in s
;"Input: subStr -- the string to be searched for in s
;" s -- the string to search
;" count -- OPTIONAL, the instance to return pos of (1=1st, 2=2nd, etc.)
;" if count=2 and only 1 instance exists, then 0 returned
;"Result: the beginning position, or 0 if not found
;"Note: This function differs from $find in that $find returns the pos of the
;" first character AFTER the subStr
set count=$get(count,1)
new result set result=0
new instance set instance=1
PS1
set result=$find(s,subStr,result+1)
if result>0 set result=result-$length(subStr)
if count>instance set instance=instance+1 goto PS1
quit result
ArrayPos(array,s)
;"Purpose: return the index position of s in array
;"...
quit
DiffPos(s1,s2)
;"Purpose: Return the position of the first difference between s1 and s2
;"Input -- s1, s2 : The strings to compare.
;"result: the position (in s1) of the first difference, or 0 if no difference
new l set l=$length(s1)
if $length(s2)>l set l=$length(s2)
new done set done=0
new i for i=1:1:l do quit:(done=1)
. set done=($extract(s1,1,i)'=$extract(s2,1,i))
new result set result=0
if done=1 set result=i
quit result
DiffWPos(Words1,Words2)
;"Purpose: Return the index of the first different word between Words arrays
;"Input: Words1,Words2 -- the array of words, such as would be made
;" by CleaveToArray^TMGSTUTL
;"Returns: Index of first different word in Words1, or 0 if no difference
new l set l=+$get(Words1("MAXNODE"))
if +$get(Words2("MAXNODE"))>l set l=+$get(Words2("MAXNODE"))
new done set done=0
new i for i=1:1:l do quit:(done=1)
. set done=($get(Words1(i))'=$get(Words2(i)))
new result
if done=1 set result=i
else set result=0
quit result
SimStr(s1,p1,s2,p2)
;"Purpose: return the matching string in both s1 and s2, starting
;" at positions p1 and p2.
;" Example: s1='Tom is 12 years old', p1=7
;" s2='Bill will be 12 years young tomorrow' p2=13
;" would return ' 12 years '
new ch1,ch2,offset,result,done
set result="",done=0
for offset=0:1:9999 do quit:(done=1)
. set ch1=$extract(s1,p1+offset)
. set ch2=$extract(s2,p2+offset)
. if (ch1=ch2) set result=result_ch1
. else set done=1
quit result
SimWord(Words1,p1,Words2,p2)
;"Purpose: return the matching words in both words array 1 and 2, starting
;" at word positions p1 and p2. This function is different from
;" SimStr in that it works with whole words
;" Example:
;" Words1(1)=Tom Words2(1)=Bill
;" Words1(2)=is Words2(2)=will
;" Words1(3)=12 Words2(3)=be
;" Words1(4)=years Words2(4)=12
;" Words1(5)=old Words2(5)=years
;" Words1("MAXNODE")=5 Words2(6)=young
;" Words2(7)=tomorrow
;" Words1("MAXNODE")=7
;" This will return 3, (where '12 years' starts)
;" if p1=3 and p2=4 would return '12 years'
;"Note: A '|' will be used as word separator when constructing result
;"Input: Words1,Words2 -- the array of words, such as would be made
;" by CleaveToArray^TMGSTUTL. e.g.
;" p1,p2 -- the index of the word in Words array to start with
;"result: (see example)
new w1,w2,offset,result,done
set result="",done=0
for offset=0:1:$get(Words1("MAXNODE")) do quit:(done=1)
. set w1=$get(Words1(offset+p1))
. set w2=$get(Words2(offset+p2))
. if (w1=w2)&(w1'="") do
. . if (result'="") set result=result_"|"
. . set result=result_w1
. else set done=1
quit result
SimPos(s1,s2,DivStr,pos1,pos2,MatchStr)
;"Purpose: return the first position that two strings are similar. This means
;" the first position in string s1 that characters match in s2. A
;" match will be set to mean 3 or more characters being the same.
;" Example: s1='Tom is 12 years old'
;" s2='Bill will be 12 years young tomorrow'
;" This will return 7, (where '12 years' starts)
;"Input: s1,s2 -- the two strings to compare
;" DivStr -- OPTIONAL, the character to use to separate the answers
;" in the return string. Default is '^'
;" pos1 -- OPTIONAL, an OUT PARAMETER. Returns Pos1 from result
;" pos2 -- OPTIONAL, an OUT PARAMETER. Returns Pos2 from result
;" MatchStr -- OPTIONAL, an OUT PARAMETER. Returns MatchStr from result
;"Results: Pos1^Pos2^MatchStr Pos1=position in s1, Pos2=position in s2,
;" MatchStr=the matching Str
set DivStr=$get(DivStr,"^")
new startPos,subStr,found,s2Pos
set found=0,s2Pos=0
for startPos=1:1:$length(s1) do quit:(found=1)
. set subStr=$extract(s1,startPos,startPos+3)
. set s2Pos=$$Pos(subStr,s2)
. set found=(s2Pos>0)
new result
if found=1 do
. set pos1=startPos,pos2=s2Pos
. set MatchStr=$$SimStr(s1,startPos,s2,s2Pos)
else do
. set pos1=0,pos2=0,MatchStr=""
set result=pos1_DivStr_pos2_DivStr_MatchStr
quit result
SimWPos(Words1,Words2,DivStr,p1,p2,MatchStr)
;"Purpose: return the first position that two word arrays are similar. This means
;" the first index in Words array 1 that matches to words in Words array 2.
;" A match will be set to mean the two words are equal
;" Example:
;" Words1(1)=Tom Words2(1)=Bill
;" Words1(2)=is Words2(2)=will
;" Words1(3)=12 Words2(3)=be
;" Words1(4)=years Words2(4)=12
;" Words1(5)=old Words2(5)=years
;" Words1("MAXNODE")=5 Words2(6)=young
;" Words2(7)=tomorrow
;" Words2("MAXNODE")=7
;" This will return 3, (where '12 years' starts)
;"Input: Words1,Words2 -- the two arrays to compare
;" DivStr -- OPTIONAL, the character to use to separate the answers
;" in the return string. Default is '^'
;" pos1 -- OPTIONAL, an OUT PARAMETER. Returns Pos1 from result
;" pos2 -- OPTIONAL, an OUT PARAMETER. Returns Pos2 from result
;" MatchStr -- OPTIONAL, an OUT PARAMETER. Returns MatchStr from result
;"Results: Pos1^Pos2^MatchStr Pos1=position in Words1, Pos2=position in Words2,
;" MatchStr=the first matching Word or phrase
;" Note: | will be used as a word separator for phrases.
set DivStr=$get(DivStr,"^")
new startPos,word1,found,w2Pos
set found=0,s2Pos=0
for startPos=1:1:+$get(Words1("MAXNODE")) do quit:(found=1)
. set word1=$get(Words1(startPos))
. set w2Pos=$$IndexOf^TMGMISC($name(Words2),word1)
. set found=(w2Pos>0)
if found=1 do
. set p1=startPos,p2=w2Pos
. set MatchStr=$$SimWord(.Words1,p1,.Words2,p2)
else do
. set p1=0,p2=0,MatchStr=""
new result set result=p1_DivStr_p2_DivStr_MatchStr
quit result
DiffStr(s1,s2,DivChr)
;"Purpose: Return how s1 differs from s2. E.g.
;" s1='Today was the birthday of Bill and John'
;" s2='Yesterday was the birthday of Tom and Sue'
;" results='Today^1^Bill^26^John^35'
;" This means that 'Today', starting at pos 1 in s1 differs
;" from s2. And 'Bill' starting at pos 26 differs from s2 etc..
;"Input: s1,s2 -- the two strings to compare
;" DivStr -- OPTIONAL, the character to use to separate the answers
;" in the return string. Default is '^'
;"Results: DiffStr1^pos1^DiffStr2^pos2^...
set DivChr=$get(DivChr,"^")
new result set result=""
new offset set offset=0
new p1,p2,matchStr,matchLen
new diffStr,temp
DSLoop
set temp=$$SimPos(s1,s2,DivChr,.p1,.p2,.matchStr)
;"Returns: Pos1^Pos2^MatchStr Pos1=pos in s1, Pos2=pos in s2, MatchStr=the matching Str
if p1=0 set:(s1'="") result=result_s1_DivChr_(+offset) goto DSDone
set matchLen=$length(matchStr)
if p1>1 do
. set diffStr=$extract(s1,1,p1-1)
. set result=result_diffStr_DivChr_(1+offset)_DivChr
set offset=offset+(p1+matchLen-1)
set s1=$extract(s1,p1+matchLen,9999) ;"trim s1
set s2=$extract(s2,p2+matchLen,9999) ;"trim s2
goto DSLoop
DSDone
quit result
DiffWords(Words1,Words2,DivChr)
;"Purpose: Return how Word arrays Words1 differs from Words2. E.g.
;" Example:
;" Words1(1)=Tom Words2(1)=Bill
;" Words1(2)=is Words2(2)=will
;" Words1(3)=12 Words2(3)=be
;" Words1(4)=years Words2(4)=12
;" Words1(5)=old Words2(5)=years
;" Words1("MAXNODE")=5 Words2(6)=young
;" Words2(7)=tomorrow
;" Words1("MAXNODE")=7
;"
;" s1='Today was the birthday of Bill and John'
;" s2='Yesterday was the birthday of Tom and Sue'
;" results='Tom is^1^old^5'
;" This means that 'Tom is', starting at pos 1 in Words1 differs
;" from Words2. And 'old' starting at pos 5 differs from Words2 etc..
;"Input: Words1,Words2 -- PASS BY REFERENCE. The two word arrays to compare
;" DivStr -- OPTIONAL, the character to use to separate the answers
;" in the return string. Default is '^'
;"Note: The words in DiffStr are divided by "|"
;"Results: DiffStr1A>DiffStr1B^pos1>pos2^DiffStr2A>DiffStr2B^pos1>pos2^...
;" The A DiffStr would be what the value is in Words1, and
;" the B DiffStr would be what the value is in Words2, or @ if deleted.
set DivChr=$get(DivChr,"^")
new result set result=""
new trimmed1,trimmed2 set trimmed1=0,trimmed2=0
new p1,p2,matchStr,matchLen
new diffStr1,diffStr2,temp
new tWords1,tWords2
merge tWords1=Words1
merge tWords2=Words2
new i,len1,len2,trimLen1,trimLen2
new diffPos1,diffPos2
set len1=+$get(tWords1("MAXNODE"))
set len2=+$get(tWords2("MAXNODE"))
DWLoop
set temp=$$SimWPos(.tWords1,.tWords2,DivChr,.p1,.p2,.matchStr)
;"Returns: Pos1^Pos2^MatchStr Pos1=pos in s1, Pos2=pos in s2, MatchStr=the matching Str
;"Possible return options:
;" p1=p2=0 -- two strings have nothing in common
;" p1=p2=1 -- first word of each string is the same
;" p1=p2=X -- words 1..(X-1) differ from each other.
;" p1>p2 -- e.g. EXT REL TAB --> XR TAB
;" p1 EXT REL TAB
if (p1=0)&(p2=0) do
. set diffStr1=$$CatArray(.tWords1,1,len1,"|")
. set diffStr2=$$CatArray(.tWords2,1,len2,"|")
. set trimLen1=len1,trimLen2=len2
. set diffPos1=1+trimmed1
. set diffPos2=1+trimmed2
else if (p1=1)&(p2=1) do
. set diffStr1="@",diffStr2="@"
. set trimLen1=1,trimLen2=1
. set diffPos1=0,diffPos2=0
else do
. set diffStr1=$$CatArray(.tWords1,1,p1-1,"|")
. set diffStr2=$$CatArray(.tWords2,1,p2-1,"|")
. set trimLen1=p1-1,trimLen2=p2-1
. set diffPos1=1+trimmed1,diffPos2=1+trimmed2
if diffStr1="" set diffStr1="@"
if diffStr2="" set diffStr2="@"
if '((diffStr1="@")&(diffStr1="@")) do
. set:(result'="")&($extract(result,$length(result))'=DivChr) result=result_DivChr
. set result=result_diffStr1_">"_diffStr2_DivChr
. set result=result_diffPos1_">"_diffPos2
do ListTrim^TMGMISC("tWords1",1,trimLen1,"MAXNODE")
do ListTrim^TMGMISC("tWords2",1,trimLen2,"MAXNODE")
set trimmed1=trimmed1+trimLen1
set trimmed2=trimmed2+trimLen2
if ($get(tWords1("MAXNODE"))=0)&($get(tWords2("MAXNODE"))=0) goto DWDone
goto DWLoop
DWDone
quit result
CatArray(Words,i1,i2,DivChr)
;"Purpose: For given word array, return contatenated results from index1 to index2
;"Input: Words -- PASS BY REFERENCE. Array of Words, as might be created by CleaveToArray
;" i1 -- the index to start concat at
;" i2 -- the last index to include in concat
;" DivChr -- OPTIONAL. The character to used to separate words. Default=" "
new result set result=""
set DivChr=$get(DivChr," ")
new i for i=i1:1:i2 do
. new word set word=$get(Words(i))
. if word="" quit
. set:(result'="")&($extract(result,$length(result))'=DivChr) result=result_DivChr
. set result=result_word
quit result
QTPROTECT(S) ;"SAAC compliant entry point
quit $$QtProtect(.S)
QtProtect(s)
;"Purpose: Protects quotes by converting all quotes do double quotes (" --> "")
;"Input : s -- The string to be modified. Original string is unchanged.
;"Result: returns a string with all instances of single instances of quotes
;" being replaced with two quotes.
new tempS
set tempS=$$Substitute($get(s),"""""","<^@^>") ;"protect original double quotes
set tempS=$$Substitute(tempS,"""","""""")
set tempS=$$Substitute(tempS,"<^@^>","""""") ;"reverse protection
quit tempS
GetStrPos(s,StartPos,P1,P2) ;"INCOMPLETE!!
;"Purpose: return position of start and end of a string (marked by starting
;" and ending quote. Search is started at StartPos.
;" Example: if s='She said "Hello" to Bill', and StartPos=1
;" then P1 should be returned as 10, and P2 as 16
;"Input: s -- the text to be
;" StartPos -- the position to start the search at. Optional: default=1
;" P1 -- PASS BY REFERENCE, an Out Parameter
;" P2 -- PASS BY REFERENCE, an Out Parameter
;"Results: None
;"Output: P1 and P2 are returned as per example above, or 0 if not quotes in text
set P1=0,P2=0
if s'["""" goto GSPDone
set StartPos=+$get(StartPos,1)
new tempS set tempS=$extract(s,StartPos,$length(s))
set tempS=$$Substitute(tempS,"""""",$char(1)_$char(1))
;"FINISH... NOT COMPLETED...
GSPDone
quit
InQt(s,Pos)
;"Purpose: to return if a given character, in string(s), is insided quotes
;" e.g. s='His name is "Bill," OK?' and if p=14, then returns 1
;" (note the above string is usually stored as:
;" "His name is ""Bill,"" OK?" in the text editor, BUT in the
;" strings that will be passed here I will get only 1 quote character
;"Input: s -- the string to scan
;" Pos -- the position of the character in question
;"Results: 0 if not inside quotes, 1 if it is.
;"NOTE: if Pos points to the bounding quotes, the result is 0
new inQt set inQt=0
if (Pos>$length(s))!(Pos<1) goto IQtDone
new p set p=$find(s,"""")-1
if p returns "hungry"
;"Example: s="Find('Purple')", Pos=8, OpenDiv="(", CloseDiv=")" --> returns "'Purple'"
;"Input: s -- the string containing the source sentence
;" Pos -- the index of a character anywhere inside desired word.
;" OpenDiv -- OPTIONAL, default is " " this is what marks the start of the word.
;" NOTE: if $length(OpenDiv)>1, then OpenDiv is considered
;" to be a SET of characters, any of which can be used
;" as a opening character.
;" CloseDiv -- OPTIONAL, default is " " this is what marks the end of the word.
;" NOTE: if $length(CloseDiv)>1, then CloseDiv is considered
;" to be a SET of characters, any of which can be used
;" as a closing character.
;"Results: returns desired word, or "" if problem.
;
new result set result=""
set OpenDiv=$get(OpenDiv," ")
set CloseDiv=$get(CloseDiv," ")
set Pos=+$get(Pos) if Pos'>0 goto GWdDone
new p1,p2,len,i
set len=$length(s)
for p2=Pos:1:len if CloseDiv[$extract(s,p2) set p2=p2-1 quit
for p1=Pos:-1:1 if OpenDiv[$extract(s,p1) set p1=p1+1 quit
set result=$extract(s,p1,p2)
GWdDone quit result
MATCHXTR(s,DivCh,Group,Map,Restrict)
;"Purpose: Provide a SAAC compliant (all upper case) entry point) for MatchXtract
quit $$MatchXtract(.s,.DivCh,.Group,.Map,.Restrict)
;
MatchXtract(s,DivCh,Group,Map,Restrict)
;"Purpose to extract a string bounded by DivCh, honoring matching encapsulators
;"Note: the following markers are honored as paired encapsulators:
;" ( ), { }, | |, < >, # #, [ ],
;" To specify which set to use, DivCh should specify only OPENING character
;"E.g. DivCh="{"
;" s="Hello {There}" --> return "There"
;" s="Hello {There {nested braces} friend}" --> return "There {nested braces} friend"
;" DivCh="|"
;" s="Hello |There|" --> "There"
;" s="Hello |There{|friend|}|" --> "There{|friend|}"
;" Notice that the second "|" was not paired to the first, because an opening brace was first.
;"Input: s -- The string to evaluate
;" DivCh -- The opening character of the encapsulator to use
;" Group -- OPTIONAL. Default is 1. If line has more than one set of encapsulated entries, which group to get from
;" Map -- OPTIONAL. PASS BY REFERENCE. If function is to be called multiple times,
;" then a prior Map variable can be passed to speed processing.
;" Restrict -- OPTIONAL. A string of allowed opening encapsulators (allows others to be ignored)
;" e.g. "{(|" <-- will cause "<>#[]" to be ignored
;"Results: Returns extracted string.
if $data(Map)=0 do MapMatch(s,.Map,.Restrict)
set Group=$get(Group,1)
set DivCh=$get(DivCh)
new Result set Result=""
new i set i=0
for set i=$order(Map(Group,i)) quit:(i="")!(Result'="") do
. if DivCh'=$get(Map(Group,i)) quit
. new p,j
. for j=1,2 set p(j)=+$get(Map(Group,i,"Pos",j))
. set Result=$extract(s,p(1)+1,p(2)-1)
quit Result
MapMatch(s,Map,Restrict)
;"Purpose to map a string with nested braces, parentheses etc (encapsulators)
;"Note: the following markers are honored as paired encapsulators:
;" ( ), { }, | |, < >, # #, " "
;"Input: s -- string to evaluate
;" Map -- PASS BY REFERENCE. An OUT PARAMETER. Prior values are killed. Format:
;" Map(Group,Depth)=OpeningSymbol
;" Map(Group,Depth,"Pos",1)=index of opening symbol
;" Map(Group,Depth,"Pos",2)=index of paired closing symbol
;" Restrict -- OPTIONAL. A string of allowed opening encapsulators (allows others to be ignored)
;" e.g. "{(|" <-- will cause "<>#[]" to be ignored
;"E.g. s="Hello |There{|friend|}|"
;" Map(1,1)="|"
;" Map(1,1,"Pos",1)=7
;" Map(1,1,"Pos",2)=23
;" Map(1,2)="{"
;" Map(1,2,"Pos",1)=13
;" Map(1,2,"Pos",2)=22
;" Map(1,3)="|"
;" Map(1,3,"Pos",1)=14
;" Map(1,3,"Pos",2)=21
;"Eg. s="Hello |There{|friend|}| This is more (and I (want { to say} !) OK?)"
;" map(1,1)="|"
;" map(1,1,"Pos",1)=7
;" map(1,1,"Pos",2)=23
;" map(1,2)="{"
;" map(1,2,"Pos",1)=13
;" map(1,2,"Pos",2)=22
;" map(1,3)="|"
;" map(1,3,"Pos",1)=14
;" map(1,3,"Pos",2)=21
;" map(2,1)="("
;" map(2,1,"Pos",1)=39
;" map(2,1,"Pos",2)=68
;" map(2,2)="("
;" map(2,2,"Pos",1)=46
;" map(2,2,"Pos",2)=63
;" map(2,3)="{"
;" map(2,3,"Pos",1)=52
;" map(2,3,"Pos",2)=60
;"Results: none
set Restrict=$get(Restrict,"({|<#""")
new Match,Depth,i,Group
if Restrict["(" set Match("(")=")"
if Restrict["{" set Match("{")="}"
if Restrict["|" set Match("|")="|"
if Restrict["<" set Match("<")=">"
if Restrict["#" set Match("#")="#"
if Restrict["""" set Match("""")=""""
kill Map
set Depth=0,Group=1
for i=1:1:$length(s) do
. new ch set ch=$extract(s,i)
. if ch=$get(Map(Group,Depth,"Closer")) do quit
. . set Map(Group,Depth,"Pos",2)=i
. . kill Map(Group,Depth,"Closer")
. . set Depth=Depth-1
. . if Depth=0 set Group=Group+1
. if $data(Match(ch))=0 quit
. set Depth=Depth+1
. set Map(Group,Depth)=ch
. set Map(Group,Depth,"Closer")=Match(ch)
. set Map(Group,Depth,"Pos",1)=i
quit
CmdChStrip(s)
;"Purpose: Strip all characters < #32 from string.
new Codes,i,result
set Codes=""
for i=1:1:31 set Codes=Codes_$char(i)
set result=$translate(s,Codes,"")
quit result
StrBounds(s,p)
;"Purpose: given position of start of string, returns index of end of string
;"Input: s -- the string to eval
;" p -- the index of the start of the string
;"Results : returns the index of the end of the string, or 0 if not found.
new result set result=0
for p=p+1:1 quit:(p>$length(s))!(result>0) do
. if $extract(s,p)'="""" quit
. set p=p+1
. if $extract(s,p)="""" quit
. set result=p-1
quit result
NonWhite(s,p)
;"Purpose: given starting position, return index of first non-whitespace character
;" Note: either a " " or a TAB [$char(9)] will be considered a whitespace char
;"result: returns index if non-whitespace, or index past end of string if none found.
new result,ch,done
for result=p:1 quit:(result>$length(s)) do quit:done
. set ch=$extract(s,result)
. set done=(ch'=" ")&(ch'=$char(9))
quit result
Pad2Pos(Pos,ch)
;"Purpose: return a string that can be used to pad from the current $X
;" screen cursor position, up to Pos, using char Ch (optional)
;"Input: Pos -- a screen X cursor position, i.e. from 1-80 etc (depending on screen width)
;" ch -- Optional, default is " "
;"Result: returns string of padded characters.
new width set width=+$get(Pos)-$X if width'>0 set width=0
quit $$LJ^XLFSTR("",width,.ch)
HTML2TXT(Array)
;"Purpose: text a WP array that is HTML formatted, and strip , and
;" return in a format of 1 line per array node.
;"Input: Array -- PASS BY REFERENCE. This array will be altered.
;"Results: none
;"NOTE: This conversion causes some loss of HTML tags, so a round trip
;" conversion back to HTML would fail.
;"Called from: TMGTIUOJ.m
new outArray,outI
set outI=1
;"Clear out confusing non-breaking spaces.
new spec
set spec(" ")=" "
set spec("<")="<"
set spec(">")=">"
set spec("&")="&"
set spec(""")=""""
new line set line=0
for set line=$order(Array(line)) quit:(line="") do
. new lineS set lineS=$get(Array(line,0))
. set Array(line,0)=$$REPLACE^XLFSTR(lineS,.spec)
new s2 set s2=""
new line set line=0
for set line=$order(Array(line)) quit:(line="") do
. new lineS set lineS=s2_$get(Array(line,0))
. set s2=""
. for do quit:(lineS'["<")
. . if (lineS["
")&($piece(lineS,"
",1)'["
") do quit
. . . set outArray(outI,0)=$piece(lineS,"
",1)
. . . set outI=outI+1
. . . set outArray(outI,0)="" ;"Add blank line to create paragraph break.
. . . set outI=outI+1
. . . set lineS=$piece(lineS,"
",2,999)
. . if (lineS["
")&($piece(lineS,"
",1)'["
") do quit
. . . set outArray(outI,0)=$piece(lineS,"",1)
. . . set outI=outI+1
. . . set outArray(outI,0)="" ;"Add blank line to create paragraph break.
. . . set outI=outI+1
. . . set lineS=$piece(lineS,"",2,999)
. . if (lineS["")&($piece(lineS,"",1)'["
") do quit
. . . set outArray(outI,0)=$piece(lineS,"",1) ;" _""
. . . set outI=outI+1
. . . set outArray(outI,0)="" ;"Add blank line to create paragraph break.
. . . set outI=outI+1
. . . set lineS=$piece(lineS,"",2,999)
. . if lineS["
" do quit
. . . set outArray(outI,0)=$piece(lineS,"
",1)
. . . set outI=outI+1
. . . set lineS=$piece(lineS,"
",2,999)
. . set s2=lineS,lineS=""
. set s2=s2_lineS
if s2'="" do
. set outArray(outI,0)=s2
. set outI=outI+1
kill Array
merge Array=outArray
quit
TrimTags(lineS)
;"Purpose: To cut out HTML tags (e.g. <...>) from lineS, however, is protected
;"Input: lineS : the string to work on.
;"Results: the modified string
;"Called from: TMGTIUOJ.m
new result,key,spec
set spec("")="[no data]"
set result=$$REPLACE^XLFSTR(lineS,.spec)
for quit:((result'["<")!(result'[">")) do
. new partA,partB
. set partA=$piece(result,"<",1)
. new temp set temp=$extract(result,$length(partA)+1,999)
. set partB=$piece(temp,">",2,99)
. set result=partA_partB
quit result
IsHTML(IEN8925)
;"Purpose: to specify if the text held in the REPORT TEXT field is HTML markup
;"Input: IEN8925 -- record number in file 8925
;"Results: 1 if HTML markup, 0 otherwise.
;"Note: This is not a perfect test.
;
new result set result=0
new Done set Done=0
new line set line=0
for set line=$order(^TIU(8925,IEN8925,"TEXT",line)) quit:(line="")!Done do
. new lineS set lineS=$$UP^XLFSTR($get(^TIU(8925,IEN8925,"TEXT",line,0)))
. if (lineS["") set Done=1,result=1 quit
quit result