I have a database field with strings like this
oh the sea OToole was right
I like ramen but
Rowing like a Blue but not an artist
They are actual words separated with space
I want to find to extract the first 3 words
The result would be like below
oh the sea
I like ramen
Rowing like a
I tried the following
ExtractString({tbname.field1},""," ") & " " & ExtractString({tbname.field1}," "," ") & ExtractString({tbname.field1}," "," ")
It did work for the the first two fields but not the second
I tried the one below too
split({tbname.field1}, " ")[1] & " " & split({tbname.field1}, " ")[2]
& " " & split({tbname.field1}, " ")[3]
It gives me an error saying the indice must be between 1 and the size of the array
Any insights are more than welcome
if ubound(Split({tbname.field1})) < 3 then
Join(Split({tbname.field1})[1 to ubound(Split({tbname.field1}))]," ")
else Join(Split({tbname.field1})[1 to 3]," ")
** edited to reflect data is contained in a single row, rather than 3 separate rows
Try:
// defined delimiter
Local Stringvar CRLF := Chr(10)+Chr(13);
// split CRLF-delimited string into an array
Local Stringvar Array rows := Split({Command.WORDS}, CRLF);
// the results of all the work
Local Stringvar Array results;
// process each 'row'
Local Numbervar i;
for i := 1 to ubound(rows) do (
// increment the array, then add first 3 words
Redim Preserve results[Ubound(results)+1];
results[ubound(results)]:=Join(Split(rows[i])[1 to 3]," ")
);
// create CRLF-delimited string
Join(results, CRLF);
Related
I have a super simple formula. The problem is that sometimes the data doesn't have a second value, or sometimes the value is blank.
Split ({PO_RECEIVE.VENDOR_LOT_ID}," ")[2]
ID
111 222
123
123 222
I was thinking if I could come up with some logic to figure out whether the string has multiple value's it would solve my problem, but haven't quiet found what I'm looking for:
If {PO_RECEIVE.VENDOR_LOT_ID} = SingleOrBlankString then
{PO_RECEIVE.VENDOR_LOT_ID} else
Split ({PO_RECEIVE.VENDOR_LOT_ID}," ")[2]
Better Example Data:
3011111*42011111111
2711 00291111111
711111//12111111111
/J1111 69111111111
170111
If the string can contain a maximum of two values, separated by a space, then you can check if the string contains a space using the InStr function:
If InStr({PO_RECEIVE.VENDOR_LOT_ID}, " ") > 0 Then
{PO_RECEIVE.VENDOR_LOT_ID}
Else
Split ({PO_RECEIVE.VENDOR_LOT_ID}," ")[2]
If there can be multiple spaces between the parts you can use following formulas to get the values:
Left part:
This function returns the left part of the string until the first space.
If InStr({PO_RECEIVE.VENDOR_LOT_ID}, " ") > 0 Then
Left({PO_RECEIVE.VENDOR_LOT_ID}, InStr({PO_RECEIVE.VENDOR_LOT_ID}, " "))
Right part:
This function returns the right part of the string after the last space.
The InStrRev-function returns the position of the last space because it searches the string backwards.
The Len-function returns the length of the string.
[length] - [position of last space] = [length of the right part]
If InStr({PO_RECEIVE.VENDOR_LOT_ID}, " ") > 0 Then
Right({PO_RECEIVE.VENDOR_LOT_ID}, Len({PO_RECEIVE.VENDOR_LOT_ID}) - InStrRev(testString, " "))
newbie question here.
I need to create a list. but my problem is what is the best way to not start with a comma?
eg:
output to /usr2/appsrv/test/Test.txt.
def var dTextList as char.
for each emp no-lock:
dTextList = dTextList + ", " + emp.Name.
end.
put unformatted dTextList skip.
output close.
then my end result is
, jack, joe, brad
what is the best way to get rid of the leading comma?
thank you
Here's one way:
ASSIGN
dTextList = dTextList + ", " WHEN dTextList > ""
dTextList = dTextList + emp.Name
.
This does it without any conditional logic:
for each emp no-lock:
csv = csv + emp.Name + ",".
end.
right-trim( csv, "," ).
or you can do this:
for each emp no-lock:
csv = substitute( "&1,&2" csv, emp.Name ).
end.
trim( csv, "," ).
Which also has the advantage of playing nicely with unknown values (the ? value...)
TRIM() trims both sides, LEFT-TRIM() only does leading characters and RIGHT-TRIM() gets trailing characters.
My vanilla list:
output to /usr2/appsrv/test/Test.txt.
def var dTextList as char no-undo.
for each emp no-lock:
dTextList = substitute( "&1, &2", dTextList, emp.Name )
end.
put unformatted substring( dTextList, 3 ) skip.
output close.
substitute prevents unknowns from wiping out list
keep list delimiter checking outside of loop
generally leave the list delimiter prefixed unless the prefix really needs to go as in the case when outputting it
When using delimited lists often you may want to consider a creating a list class to remove this irrelevant noise out of your code so that you can functionally just add an item to a list and export a list without tinkering with these details every time.
I usually do
ASSIGN dTextList = dTextList + (if dTextList = '' then '' else ',') + emp.name.
I come up (well my colleague did) he come up with this:
dTextList = substitute ("&1&3&2", dTextList, emp.Name, min(dTextList,",")).
But it is cool to see various ways to do this. Thank you for all the response
This results in no leading comma (delimiter) and no fiddling with trim/substring/etc
def var cDelim as char.
def var dTextList as char.
cDelim = ''.
for each emp no-lock:
dTextList = dTextList + cDelim + emp.Name.
cDelim = ','.
end.
I have a column of strings that look like this:
Target Host: dcmxxxxxxc032.erc.nam.fm.com Target Name:
dxxxxxxgsc047.erc.nam.fm.com Filesystem /u01 has 4.98% available space
- fallen below warning (20) or critical (5) threshold.
The column name is [Description]
The substring I would like returned is (dxxxxxxgsc047.erc.nam.fm.com)
The only consistency in this data is that the desired string occurs between the 5th and 6th occurrences of spaces " " in the string, and after the phrase "Target Name: " The length of the substring varies, but it always ends in another " ", hence my attempt to grab the substring between the 5th and 6th spaces.
I have tried
MID([Description],((FIND([Description],"Target Name: "))+13),FIND([Description]," ",((FIND([Description],"Target Name"))+14)))
But that does not work.
(Edit: We use Tableau 8.2, the Tableau 9 only functions can't be part of the solution, thanks though!)
Thank you in advance for your help.
In Tableau 9 you can use regular expressions in formulas, it makes the task simpler:
REGEXP_EXTRACT([Description], "Target Name: (.*?) ")
Alternatively in Tableau 9 you can use the new FINDNTH function:
MID(
[Description],
FINDNTH([Description]," ", 5) + 1,
FINDNTH([Description]," ", 6) - FINDNTH([Description]," ", 5) - 1
)
Prior to Tableau 9 you'd have to use string manipulation methods similar to what you've tried, just need to be very careful with arithmetic and providing the right arguments (the third argument in MID is length, not index of the end character, so we need to subtract the index of the start character):
MID(
[Description]
, FIND([Description], "Target Name:") + 13
, FIND([Description], " ", FIND([Description], "Target Name:") + 15)
- (FIND([Description], "Target Name:") + 13)
)
Well, you need to find "Target name: " and then the " " after it, not so hard. I'll split in 3 fields just to be more clear (you can mix everything in a single field). BTW, you were in the right direction, but the last field on MID() should be the string length, not the char position
[start]:
FIND([Description],"Target name: ")+13
[end]:
FIND([Description]," ",[start])
And finally what you need:
MID([Description],[start]+1,[end]-[start]-1)
This should do. If you want to pursue the 5th and 6th " " approach, I would recommend you to find each of the " " until the 6th.
[1st]:
FIND([Description], " ")
[2nd]:
FIND([Description], " ",[1st] + 1)
And so on. Then:
MID([Description],[5th]+1,[6th]-[5th]-1)
A simple solution -
SPLIT( [Description], " ", 3 )
This returns a substring from the Description string, using the space delimiter character to divide the string into a sequence of tokens.
The string is interpreted as an alternating sequence of delimiters and
tokens. So for the string abc-defgh-i-jkl, where the delimiter
character is ‘-‘, the tokens are abc, defgh, i and jlk. Think of these
as tokens 1 through 4. SPLIT returns the token corresponding to the
token number. When the token number is positive, tokens are counted
starting from the left end of the string; when the token number is
negative, tokens are counted starting from the right. -
Tableau String Functions
I don't know Tableau, but perhaps something like this?
MID(
MID([Description], FIND([Description],"Target Name: ") + 13, 50),
1,
FIND(MID([Description], FIND([Description],"Target Name: ") + 13, 50), " ")
)
I have one field in a dataset which has a multi-line textbox value. I want to split that record, store it into an array, and when I fetch the value from the array by a for-loop, I want to prepend a "*" to each line. I have written a formula for that but it's working only for 2 values. After that it's not working and I'm not able to get how to retrieve the value like this.
I want the result to be:
* 123
* 234
* 786
But I'm getting the result:
*123
234
786
my formula is
Local StringVar y;
Local StringVar x;
Local NumberVar i;
y := ""+ chrw(10);
x := y;
Stringvar Array strings := Split({Touche.Concerns}, "\r\n");
Stringvar Array numbers;
For i :=1 To Ubound(strings) Do
(
y := y + chrw(10)+ "$" + strings[i];
);
y;
Instead of a long formula which breaks into arrays and manipulates each line, why not just replace the line breaks with a line break and the asterisk?
"* " & replace(trim({Touche.Concerns}), "\r\n", "\r\n* ");
The leading '*' is to place the char on the first line and the trim function is called to remove any trailing line breaks (so there won't be a line with just the asterisk).
As a side note, use & when concatenating strings and not the + char. Use the + can sometimes cause coercion to where numeric values would be added together. For example "12" + "34" would yield 46 instead of 1234. The & char ensures string concatenation is used.
using Crystal XI
I have two arrays - one captures a list of timepoints the other captures the times associated with them.
I need to associate the two so that the output looks like
timepoint[1] - time [1] - timepoint[2] - timepoint[2];
timepoint[3] - time[3] - timepoint[4] - timepoint[4];
so i wronte the following code - the arrays are intitialized in the header then loaded with data in the details section and then displayed in the group footer (three formula trick). I can display the data in the two arrays seperatly ok
(as timepoint[1], timepoint[2], etc)
the issue only arrises when trying to combine the two. the code below only prints the last two records in the array for the gorup instead of all of the records.
so if there are 5 timepoints and 5 times the code below displays
timepoint[4]-time[4] - timepoint[5]-time[5]
I will have to eventually perform a calculation between the two associated date times but for now just trying to get the association and display working.
Shared stringVar array Timepoints;
Shared DateTimeVar array Times;
local stringVar combineStr;
local numbervar i;
For i:=1 to UBound(Times)-2 do
(combineStr := Timepoints[i] + ','+ totext(Times[i]) + '-' +
Timepoints[i+1] + totext(Times[i+1]) + ',');
combineStr;
thanks for looking at this
You're overwriting the previous value of the combineStr variable with each iteration. You need to do this:
.
.
.
For i:=1 to UBound(Times)-2 do
(combineStr := combineStr + Timepoints[i] + ','+ totext(Times[i]) + '-' +
Timepoints[i+1] + totext(Times[i+1]) + ',');
combineStr;
A few other things: 1. You'll want to concatenate a newline character, chr(10), instead of a comma between iterations to display like your example in the question. 2. You need to add "step 2" to your for-loop otherwise you'll be printing out timepoints twice.