Coding Shortcut: Using LotusScript Replace() Without Having To Define Arrays
Imagine you have a field called "Quantity" on a document that stores how many of something you bought. You want to tell the user how many they chose but in a "wordy" way. If they chose 1, 2 or 3 then you want to display the words one, two or three respectively. Any other choice and you just show the number they chose.
In @Formula this is easy:
"You chose to buy " + @Replace(@Text(Quantity); "1":"2":"3"; "one":"two":"three") + " items."
What about in LotusScript though? There's an equivalent method called Replace() but it requires Arrays and, if you're to follow the help file examples, requires mucky coding like this:
Dim FromArray(2) As string Dim ToArray(2) As string FromArray(0) = "1" FromArray(1) = "2" FromArray(2) = "3" ToArray(0) = "one" ToArray(1) = "two" ToArray(2) = "three" Print "You chose to buy " + Replace( Cstr(document.Quantity(0)), FromArray, ToArray ) + " items."
All very well. It works. It's just so verbose. All that dimming and defining of arrays just to do a basic text replacement. I've never liked defining arrays just for this and I sometimes find myself coding things like instead:
Print "You chose to buy " If document.Quantity(0)=1 Then Print "one" Elseif document.Quantity(0)=2 Then Print "two" Elseif document.Quantity(0)=3 Then Print "three" Else Print Cstr(document.Quantity(0)) End If Print " items."
On occasion I've even resorted to tricks like this:
Print "You chose to buy " + Implode(Evaluate(|@Replace(@Text(Quantity); "1":"2":"3"; "one":"two":"three")|, document)) + " items."
All that just to avoid messing about with arrays. The Implode() trick used on the Evaluate in the line above is also there to avoid having to dim Variants all over the shop.
Well today, in a moment of (increasingly-rare) inspiration I came up with the following shorthand approach to replacing text in LotusScript:
Print "You chose to buy " + Replace( Cstr(document.Quantity(0)), Split("1, 2, 3", ", "), Split("one, two, three", ", ") ) + " items."
This will now become one of those oh-so-simple tricks that I find myself using all the time. Much like the Implode(Evaluate()) trick that Tommy Valand first highlighted and which I've used continuously ever since.
I know some developers prefer to have more lines of code if it makes it more "readable". Personally I think less is more and try to produce the least amount of code as possible. I don't have time to be defining arrays and whatnot when I've got so much else to do.
Will I be able to support it in the future though? Will another developer be able to make sense of it? In this case, yes, on both counts.
This can work in certain situations, but try replacing the number 11 with this code and see what happens (you get oneone).
The same would apply to multiple variances of the same phrase in an array.
Dan
I agree with you, that's very readable -and- maintainable.
Since there is no Array literal in LS, like there is in Java/etc, Split( [string] ) is the fastest way to get a String-array in LS.
Java:
String[] oneTwoThree = { "1", "2", "3" };
Probably a bad example thinking about it Dan.
Leaves me wondering why lotuscript replace doesn't behave exactly like its formula counterpart!?
@Replace("11"; "1":"2"; "one":"two") WILL return 11 whereas Replace("11", Split("1 2"), Split("one two")) will return "oneone" as you stated.
Is there now direct equivalent of @replace in LS?
Anyhow -- not a good example for me to use numbers but still the method is useful nonetheless if you know you don't risk running in to these "oddities".
Jake
What about using lists..?
Since a list is an array could you not do something like
Dim myWords List As String
Dim myNumber As Integer
myNumber = 2
myWords("1") = "one"
myWords("2") = "two"
myWords("3") = "three"
Messagebox( "you chose "+myWords(Format(xxx,"###0")))
Where you use the ordinal value in the array as the List Key. You still have to declare your list somewhere but you don't have to get all jiggy with Redims and variants
Steve
This is weird.
The following works:
Print Cstr(Replace( "1", Split("1, 2, 3", ", ") ,Split("one, two, three", ", ")))
This comes up with a Type Mismatch:
Dim src, dest
frmS = Split("1, 2, 3", ", ")
toS = Split("one, two, three", ", ")
Print Cstr(Replace( "1", frmS ,toS))
Never mind, I should have read the help which says:
If sourceArray, replaceArray, or replacementArray is not either a String, or an Array of type String, then a run-time type mismatch error is thrown.
Also, explains on how it works, which we are seeing in oneone for 11.
For the really complex calculations, I've used a temporary document, referenced a Form name, and then ComputeWithForm to compute various fields on the document.
Dim pref as NotesDocument
Set pref = New NotesDocument( db )
Call pref.ReplaceItemValue( "Form", "$PrefCalculations" )
{add stuff to this temporary document}
Call pref.ComputeWithForm( false, false )
{read stuff from the temporary document}
{don't save the pref doc}
That form contains Computed Fields and @Formula.
Your statement "Replace() but it requires Arrays" is not entirely correct. Had a similar approach in my sntt entry: {Link}, where Julian Robichaux pointed out that sourceArray, findArray, replacementArray may all be strings. In almost the last line in the design help your given the hint that strings actually works qoute: "If sourceArray, replaceArray, or replacementArray is not either a String, or an Array of type String, then a run-time type mismatch error is thrown."!
>> Is there no direct equivalent of @replace in LS?
ArrayReplace ?
Didn't think of that Jan.
So, to get round the anomaly of 11 becoming oneone in my - albeit poor - example you can use:
Implode(Arrayreplace( Split(document.Quantity(0)), Split("1, 2, 3", ", "), Split("one, two, three", ", ")))
What a mouthful...
You don't need Split and (0) on document.Quantity, in your latest example, as more or less all field values are arrays.
Implode(Arrayreplace( document.Quantity, Split("1, 2, 3", ", "), Split("one, two, three", ", ")))
This would -probably- also work:
Arrayreplace( document.Quantity, Split("1, 2, 3", ", "), Split("one, two, three", ", ") )(0)
But still ugly.. :)
Isn't this a good opportunity to use Select, Case statement, a little more verbose perhaps, but equally as good as the compound Else If statements...
Select Case document.Quantity(0)
Case 1 : Print "One"
Case 2 : Print "Two"
Case 3 : Print "Three"
Case Else : Print "Not Recognised"
End Select
andy
Hi Jake,
I know you are asking about Lotusscript but -out of interest -why wouldn't you use this in formula..
"You chose to buy " + @Select(Quantity;"One";"Two";"Three";"Four") + " items."
It saves having to convert quantity and only requires a single list to be updated.
I'm with Steve. Lists provide a nice combination of readability and brevity. And they're fast too (course that doesn't matter as much for something small like this).