I have a set of list values in ColdFusion variable, and I need to replace all the list values into desired text.
For Example:
<cfset headerColumnList = "FirstName,LastName,Email,FrequentGuestID,IP Address,Time Stamp Email Marketing">
<cfset a="test1">
<cfset b="test2">
<cfset c="test3">
<cfset d="test4">
<cfset e="test5">
<cfset f="test6">
<cfloop index = "ListElement" list= "#headerColumnList#" delimiters = ",">
<cfoutput>
#replaceList("#ListElement#","FirstName,LastName,Email,FrequentGuestID,IP Address,Time Stamp Email Marketing","#a#,#b#,#c#,#d#,#e#,#f#",",")#
</cfoutput>
</cfloop>
Output:
test1
test2
test3
test4
test5
Time Stamp test3 Marketing
In the above scenario. The value "Time Stamp Email Marketing" is supposed to be replaced with "test6" but I am getting in an alternative way where it is not replacing the phrase as a whole word. Can anyone tell me how do I replace the list phrases, any alternative for this?
Here you can use the ListQualify function to get exact result of an your scenario. So convert it in to qualify values and looping with that then you can replace it with your own list data. No need to change any order of a list values.
<cfset quoted = listQualify(headerColumnList,"''")>
<cfloop index = "ListElement" list= "#quoted#" delimiters = ",">
#replaceList(ListElement,quoted,"#a#,#b#,#c#,#d#,#e#,#f#")#
<br/>
</cfloop>
The code is working as written. You are seeing this because your check for "Email" in the replaceList() function is firing before the check for "Time Stamp Email Marketing". Notice the word "Email" in that string.
I don't know what your actual use case is but you can change the order of your code for this specific example to make it work like you want.
<cfset headerColumnList = "FirstName,LastName,Email,FrequentGuestID,IP Address,Time Stamp Email Marketing">
<cfset a="test1">
<cfset b="test2">
<cfset c="test3">
<cfset d="test4">
<cfset e="test5">
<cfset f="test6">
<cfloop index = "ListElement" list= "#headerColumnList#" delimiters = ",">
<cfoutput>
#replaceList("#ListElement#","FirstName,LastName,FrequentGuestID,IP Address,Time Stamp Email Marketing,Email","#a#,#b#,#d#,#e#,#f#,#c#",",")#
</cfoutput>
</cfloop>
This gives the desired output. Notice how I reordered the conditions within the replaceList() function.
Related
OK, so I've been banging my head against this one for a while and getting nowhere. I've been attempting to take the contents of a variable and parse the contained string into parts that would then be ingested into 5 separate variables. Seems simple enough right? Well, it has not proven to be simple at all, at least for me.
So I have a variable (PageContent) that contains the trimmed content from a CFHTTP request.
The PageContent variable now contains:
<tdnowrapalign=right>07/18/2020 13:00</td>
<tdalign=right>1002.12</td>
<tdalign=right>2,874,887</td>
<tdalign=right>12,766</td>
<tdalign=right>13,038</td>
It seems like there should be an easy way to write a loop that would loop over the tags in the "PageContent" variable assigning the content of each tag to a different variable. But every way I try to parse the data in the variable I either get an error (Complex object types cannot be converted to simple values.) or I end up with the content that I originally had in the "PageContent" variable repeated within the loop.
For instance, if I had a loop that would run through 5 iterations and could grab the contents of the tags assigning each to a variable then the desired result would be:
DateTime = "07/18/2020 13:00"
Elevation = "1002.12"
Storage = "2,874,887"
Outflow = "12,766"
Inflow = "13,038"
After trying every example I could find here and elsewhere online I'm now on something like my 100th attempt. Now I'm trying to use regular expressions to grab the contents of the tags and assign them to variables but no luck there. What I ended up with was the entire contents of the PageContent variable being stuffed into each one of the variables. The result was not really unexpected since I don't know of a way to differentiate between the 3 identical "tdalign" tags, but still it seems like at least the first variable would have worked since the tag was different "tdnowrapalign".
<cfset i=5/>
<cfloop index = "LoopCount" from = "1" to = #i#>
<cfif i EQ 1>
<cfset dataDateTime = Replace(PageContent, "<[tdnowrapalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 2>
<cfset elevation = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 3>
<cfset storage = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 4>
<cfset outflow = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 5>
<cfset inflow = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
</cfif>
<cfoutput>
<cfif isdefined("dataDateTime")>
dataDateTime = #dataDateTime#<br>
</cfif>
<cfif isdefined("elevation")>
elevation = #elevation#<br>
</cfif>
<cfif isdefined("storage")>
storage = #storage#<br>
</cfif>
<cfif isdefined("outflow")>
outflow = #outflow#<br>
</cfif>
<cfif isdefined("inflow")>
inflow = #inflow#<br>
</cfif>
</cfoutput>
<cfset i = i - 1>
</cfloop>
Does anyone know if there is a way to get to the desired outcome I described where I end up with 5 variables containing the contents of the tags contained within the "PageContent" variable?
One way of doing it would be like this
<cfset PageContent = '<tdnowrapalign=right>07/18/2020 13:00</td>
<tdalign=right>1002.12</td>
<tdalign=right>2,874,887</td>
<tdalign=right>12,766</td>
<tdalign=right>13,038</td>' />
<cfset data = ListToArray(PageContent, '</td>', false, true) />
<cfset DateTime = ListLast(data[1], '>') />
<cfset Elevation = ListLast(data[2], '>') />
<cfset Storage = ListLast(data[3], '>') />
<cfset Outflow = ListLast(data[4], '>') />
<cfset Inflow = ListLast(data[5], '>') />
Demo: https://trycf.com/gist/b4f3b630bd1cbdc505d07a7d79b68ef5/acf?theme=monokai
I have a two lists: One that is dynamic, based off of a recordcount of students and the other is the students..i.e., 001,002,003, etc. and 123456 (student data). I need some help being able to randomly assign students one of those numbers. For example, if I have 5 students (123456,234561, etc.), I need to be able to randomly assign 001,002, etc. to those students. So far, hitting a wall. The following is what I have so far:
<cfquery name="testjd" datasource="student">
SELECT SoonerID FROM dbo.CurrentStudentData
WHERE status = 'Student' OR status = 'JD'
</cfquery>
<cfset testList = valueList(testjd.soonerid)>
<cfset totalRecordsJd = #testjd.recordcount#>
<cfloop from="001" to="#totalRecordsJd#" index="i">
<cfset examNo = i>
<cfif len(i) is 1>
<cfset examNo = "00" & i>
<cfelseif len(i) is 2>
<cfset examNo = "0" & i>
</cfif>
<cfif not listFind(usedJDExams, examNo)>
#examNo#<!---is NOT being used!---><br/>
</cfif>
</cfloop>
CF9 makes it a little less fun than later versions. I believe this should work (except for my query mockup).
https://trycf.com/gist/3667b4a650efe702981cb934cd325b08/acf?theme=monokai
First, I create the fake query.
<!---
Simple faked up query data. This is just demo data. I think this
queryNew() syntax was first available in CF10.
--->
<cfscript>
testjd = queryNew("SoonerID", "varchar", [
["123456"],
["564798"],
["147258"],
["369741"]
]);
</cfscript>
Now that I've got a list of students who need tests, I create an array of numbers for those tests.
<!--- Create array of Available Exam Numbers --->
<cfset examNos = ArrayNew(1)>
<cfloop from=1 to=100 index="i">
<cfset examNos[i] = right('00' & i,3)>
</cfloop>
We now combine the two sets of data to get the Exam Numbers assigned to the Student.
<!--- Loop through the query and build random assignments --->
<cfloop query="#testjd#">
<!---Get random exam no.--->
<cfset examNo = examNos[randrange(1,arrayLen(examNos))]>
<!---Build struct of exam assignments--->
<cfset testAssignments[SoonerID] = examNo>
<!---Delete that num from exam array. No reuse.--->
<cfset blah = arrayDelete(examNos,examNo)>
</cfloop>
And this gives us
<cfoutput>
<cfloop collection="#testAssignments#" item="i">
For User #i#, the test is #testAssignments[i]#.<br>
</cfloop>
</cfoutput>
The unused tests are: <cfoutput>#ArrayToList(examNos)#</cfoutput>.
--------------------------------------------------------------------
For User 369741, the test is 054.
For User 147258, the test is 080.
For User 564798, the test is 066.
For User 123456, the test is 005.
The unused tests are:
001,002,003,004,006,007,008,009,010
,011,012,013,014,015,016,017,018,019,020
,021,022,023,024,025,026,027,028,029,030
,031,032,033,034,035,036,037,038,039,040
,041,042,043,044,045,046,047,048,049,050
,051,052,053,055,056,057,058,059,060
,061,062,063,064,065,067,068,069,070
,071,072,073,074,075,076,077,078,079
,081,082,083,084,085,086,087,088,089,090
,091,092,093,094,095,096,097,098,099,100.
A couple of code review notes for the OP code:
1) It's easier to work with arrays or structures than it is to work with a list.
2) cfloop from="001" to="#totalRecordsJd#": from "001" is a string that you are comparing to an integer. ColdFusion will convert "001" to a number in the background, so that it can actually start the loop. Watch out for expected data types, and make sure you use arguments as they were intended to be used.
3) cfif len(i) is 1...: First, it's less processing to build this string in one pass and them trim it - right('00' & i,3). Second (and this is a personal nitpick), is and eq do essentially the same thing, but I've always found it good practice to apply is to string-ish things and eq to number-ish things.
=====================================================================
For CF10+, I would use something like
https://trycf.com/gist/82694ff715fecd328c129b255c809183/acf2016?theme=monokai
<cfscript>
// Create array of random string assignments for ExamNo
examNos = [] ;
for(i=1; i lte 100;i++) {
arrayAppend(examNos,right('00'& i,3)) ;
}
///// Now do the work. ////
//Create a struct to hold final results
testAssignments = {} ;
// Loop through the query and build random assignments
for(row in testjd) {
// Get random exam no.
examNo = examNos[randrange(1,arrayLen(examNos))] ;
// Build struct of exam assignments
structInsert(testAssignments, row.SoonerID, examNo) ;
// Delete that num from exam array. No reuse.
arrayDelete(examNos,examNo) ;
}
</cfscript>
If it is a small query, why not just sort the records (psuedo) randomly using NEWID()? Since the records will already be randomized, you cna use query.currentRow to build the "examNo".
<cfquery name="testjd" datasource="student">
SELECT SoonerID
FROM CurrentStudentData
WHERE status IN ('Student', 'JD')
ORDER BY NewID()
</cfquery>
<cfoutput query="yourQuery">
#yourQuery.SoonerID# #NumberFormat(yourQuery.currentRow, "000000")#<br>
</cfoutput>
This is a formatted comment. After you run this query:
<cfquery name="testjd" datasource="student">
SELECT SoonerID FROM dbo.CurrentStudentData
WHERE status = 'Student' OR status = 'JD'
</cfquery>
Do this:
<cfset QueryAddColumn(testJd, "newcolumn", arrayNew(1))>
Then loop through the queries and assign values to the new column with QuerySetCell.
I'm getting cfquery result like below.This result set for one field value(single line).
Memberof =
"CN=AG-880-ExpenseReports,CN=Users,DC=alcco,DC=com, CN=HTTP Users,CN=Users,DC=alcco,DC=com, CN=WA Houses,CN=Users,DC=alcco,DC=com, CN=MTViewMeadows,CN=Users,DC=alcco,DC=com, CN=ALC0169,CN=Users,DC=alcco,DC=com, CN=ALC0069,CN=Users,DC=alcco,DC=com"
have to take as a list of number ALC0169,ALC0069 from this also i need values only 0169,0069.. from that result set.
Is there a way of doing this with coldfusion?
Here is a very straightforward string processing script that will print out the list of numbers you are looking for based on your description. Where I am printing out the numbers, you will want to capture those into an array or other structure depending on what you want to do with the data.
<cfscript>
memberOf = "CN=AG-880-ExpenseReports,CN=Users,DC=alcco,DC=com,CN=HTTP Users,CN=Users,DC=alcco,DC=com,CN=WA Houses,CN=Users,DC=alcco,DC=com,CN=MTViewMeadows,CN=Users,DC=alcco,DC=com,CN=ALC0169,CN=Users,DC=alcco,DC=com,CN=ALC0069,CN=Users,DC=alcco,DC=com";
memberOf = Replace(memberOf, "CN=Users,DC=alcco,DC=com", "", "all");
memberOf = Replace(memberOf, ",,", ",", "all");
memberOf = Replace(memberOf, "CN=", "", "all");
memberArray = ListToArray(memberOf);
</cfscript>
<cfoutput>
#memberOf#<br/><br/>
<cfloop array="#memberArray#" index="i">
<cfif Left(i, 3) eq "ALC">
#Right(i, Len(i)-3)#<br/>
</cfif>
</cfloop>
</cfoutput>
I would use list functions. Note that you can specify your own delimiter. From your other post, your cfldap tag returned a query named GroupSearch.
<cfset ALCNumbers = "">
<cfloop list = "GroupSearch.MemberOf" Index = "MemberOfThis">
<cfif ListFirst(MemberOfThis, delimiters = "=") is "CN"
and left(ListLast MemberOfThis, delimiters = "="), 3) is "ALC">
<cfset ALCNumbers = ListAppend(ALCNUmbers, mid(ListLast MemberOfThis, delimiters = "="), 4,
len(ListLast MemberOfThis, delimiters = "=") - 3)>
</cfif>
</cfloop>
This may have syntax errors because I simply typed it into the textarea. However, it shows the general idea.
I need to join the output of two separate lists together to output in a CFMAIL, and I'm wondering what the best way to approach this is.
I have two form fields: first_name and last_name
The fields have up to 5 names in each. I need to loop through those names and join the first and last names, then output them to unordered list. I am having trouble visualizing what the right approach to accomplish this is.
Can someone suggest a method in CFML (I don't know CFSCRIPT very well).
Thanks!
EDIT: I should have added that both fields will always have the exact same number of entries. Thanks to all that answered -- proof that there are a lot of ways to skin a cat :)
I would do something like
<cfloop from="1" to="#ListLen(firstnames)#" index="i">
#ListGetAt(firstnames,i)# #ListGetAt(lastnames,i)#<br>
</cfloop>
If this were a list of 5000 you would be better off putting it in a structure or an array, but for a list of ~5 this should be sufficient.
I think this would be the easiest way to accomplish this.
<!--- Create a names container --->
<cfset names = "<ul>">
<!--- Fill some dummy containers --->
<cfset first = "thomas,henry,philip,john,rony">
<cfset last = "smith,baker,crowe,ryan,jones">
<!--- Loop through the lists and append them to the container string --->
<cfloop index="name" to="#listLen(first)#" from="1">
<cfset names &= "<li>" & ListGetAt(first,name) & " " & ListGetAt(last,name) & "</li>">
</cfloop>
<cfset names &= "</ul>">
<cfoutput>#names#</cfoutput>
I would add in a check to make sure that your list values exists at each index, otherwise you will get errors. I would also add in a check to loop through whichever list is greater so that you get all values just in case someone doesn't enter exactly 5 in both:
<Cfset firstnames="Matt,Ian,Brandon,Sam,Tom">
<cfset lastnames="Jones,Smith,Weiss">
<!--- SEE WHICH LIST IS LONGER AND SET THAT AS THE ONE THAT WE WILL USE FOR THE LOOP --->
<cfif ListLen(firstnames) gte ListLen(lastnames)>
<cfset primary=firstnames>
<cfelse>
<cfset primary=lastnames>
</cfif>
<cfset myOutput="<ul>">
<cfloop from="1" to="#ListLen(primary)#" index="i">
<Cfset myOutput &= "<li>">
<cfif ListLen(firstnames) gte i>
<cfset myOutput &= ListGetAt(firstnames,i)>
</cfif>
<cfif ListLen(lastnames) gte i>
<cfset myOutput &= " " & ListGetAt(lastnames,i)>
</cfif>
<Cfset myOutput &= "</li>">
</cfloop>
<Cfset myOutput &= "</ul>">
<cfoutput>#myOutput#</cfoutput>
You could use the "list" attribute with CFLOOP although it means combining list functions within the output. Here is an example though of how it could be done and it makes the assumption the two lists will always have the same lengths. If these names are keyed in by users then I might be afraid of if they put in a comma since that would throw things off with any sort of looping.
<cfset lstFirstNames = "John,Bob,Tom,Jeff" />
<cfset lstLastNames = "Smith,Doe,Rodriguez,Horan" />
<cfloop list="#Variables.lstFirstNames#" index="FirstName" />
#FirstName# #ListGetAt(Variables.LastNames, ListFind(Variables.lstFirstNames, FirstName))#<br />
</cfloop>
try:
<cfset lstFirstNames = "John,Bob,Tom,Jeff" />
<cfset lstLastNames = "Smith,Doe,Rodriguez,Horan" />
<cfloop list="#Variables.lstFirstNames#" index="FirstName">
<cfoutput>#FirstName# #ListGetAt(Variables.lstLastNames, ListFind(Variables.lstFirstNames, FirstName))#</cfoutput><br />
</cfloop>
I have the below code:
<cfset abcList = "*,B,b,A,C,a">
<cfset abcList=ListToArray(abcList,',')>
When I output 'abcList' then it is giving me a value but when I use the 'abcList' in <cfif> it's not working. Here is the code which is creating the problem:
<cfoutput>
#abcList[1]# <!---This is giving '*' as Correct o/p--->
<cfif #abcList[1]# eq '*'> <!---Here its going in else--->
list has * at first place
<cfelse>
* is not first
</cfif>
</cfoutput>
Any suggestions on what's wrong in my code?
You don't necessarily need to convert the list to an array. If you are starting from a list variable, you may use Coldfusion list functions to do the same thing without specifying the array conversion.
<cfset abcList = "*,B,b,A,C,a">
<cfif Compare(listGetAt(abcList, 1), '*') EQ 0>
Match
<cfelse>
No Match
</cfif>
Note that most of Coldfusion's string comparisons are not case sensitive. So if you need to test that 'B' is not the same as 'b', you will need to use the compare() function or else use one of the Regular Expression string functions. In this case, compare() returns 0 if string 1 equals string 2. If you do not need case sensitivity, then you may simplify further:
<cfset abcList = "*,B,b,A,C,a">
<cfif listGetAt(abcList, 1) EQ '*'>
Match
<cfelse>
No Match
</cfif>
It also works fine for me. Perhaps you have some extra spaces in the list values? That would skew the results:
<cfset abcList = "#chr(32)#*,B,b,A,C,a">
<cfset abcList=ListToArray(abcList,',')>
<cfoutput>
The value of abcList[1] = #abcList[1]# <br/>
<cfif abcList[1] eq '*'>
list has * at first place
<cfelse>
The else condition was hit because abcList[1] is "(space)*" and not just "*"
</cfif>
</cfoutput>
Try trimming the value first. Also, the # signs around the value are not needed.
<cfif trim(abcList[1]) eq '*'>
....
</cfif>
If that does not work, display the ascii values of both characters. Perhaps they are different than you are thinking.
<cfoutput>
ASCII abcList[1] = #asc(abcList[1])# <br/>
ASCII "*" = #asc("*")# <br/>
</cfoutput>
<cfset abcList = "*,B,b,A,C,a">
<cfset abc=ListToArray(abcList)>
<cfif #abc[1]# eq "*">OK<cfelse>FAIL</cfif>
<cfif abc[1] eq "*">OK<cfelse>FAIL</cfif>
Prints "OK OK" for me. Can you re-confirm it prints something else for you?