As anyone had this issue with parsing from html file with setting <cfcase> values that contain spaces in the value? If the value contains spaces ColdFusion isn't able to find the data match in the parsed html file.
For example:
<CFCASE value="LGT RAIN">
<CFSET application.condition="Lt Rain">
</CFCASE>`
The html file has the value "LGT RAIN", but due to the way its being parsed it is not defining the city's condition. Is there a work around like check the condition prior to running your switch statements? Like if "LGT RAIN" is found then set cfset value it to "LGTRAIN".
Here is sample link that I am parsing from.
https://forecast.weather.gov/product.php?site=CAE&issuedby=CAE&product=RWR&format=CI&version=1
<CFSET WeatherData = CFHTTP.FileContent>
Code:
<!--- Check For Condition with Two Word Phrase --------------->
<CFSET condition= #GetToken("#content#",#attributes.citystring# + 1, " ")#>
<br>
<CFSET city = #attributes.citystring#>
<CFIF (condition is "LGT")
or (condition is "HVY")
or (condition is "FRZ")
or (condition is "MIX")
or (condition is "NOT")>
<CFSET condition= (
#GetToken("#content#",#attributes.citystring# + 1, " ")#
& " " &
#GetToken("#content#",#attributes.citystring# + 2, " ")#
)>
<br>
<CFSET Temp = #GetToken("#content#",#attributes.citystring# + 3, " ")#>'
.......
There is a lot of missing context on what you're trying to ultimately do with the weather you get, so I made a couple of assumptions on ways to parse through the weather block.
You'll have to actually parse the page to get that actual block, but once you do, you can use my suggestions below to split those weather elements out. I got rid of the getToken() calls, because I think that may have been more work than you needed, and was essentially led to the problem with spaces. My code is still much wordier than I intended, but I tried to make sure I wasn't using anything above CF8. I think it should all work, but I don't have a CF8 server to test on.
https://trycf.com/gist/1993243eb476a629ec25f8c6e8ddff3c/acf?theme=monokai
I've included some notes inside the code as I went along.
<!--- Create a block of the parsed weather. --->
<cfsavecontent variable="myWX">ANDERSON FAIR 49 16 26 W12G20 30.01F
LIBERTY FAIR 49 14 24 W12G21 29.99F
SPARTANBURG FAIR 45 9 23 NW12G21 30.00F
CLEMSON FAIR 48 10 21 NW13G22 30.02F
GREENVILLE FAIR 48 13 24 VRB3 29.99F
GREENWOOD FAIR 49 13 23 W10G21 30.03F
GREER FAIR 48 9 20 VRB7 29.99F
ROCK HILL FAIR 46 17 31 NW10G22 29.99F
CHESTER FAIR 45 12 26 W12G17 30.01F
LAURENS FAIR 48 16 27 NW12G18 30.01F
</cfsavecontent>
<!--- end of line character (this may change if your feed uses other eol)--->
<cfset crlf = chr(13)&chr(10)>
<!--- Make weather an array of strings for each city. --->
<cfset wxArray = ListToArray(myWX, crlf, false, true)>
My suggestion is to put the different elements in a struct, then work with that. 1 row of city weather = 1 row of Struct.
My code below assumes you are parsing rows of a 65 character fixed-width record from the HTML, which is what it appears to be when you get at the individual rows.
<!--- Loop through the new weather array and make a new array of parsed weather. --->
<!--- Create initial weather array for output. --->
<cfset newWXArray = []>
<cfloop array="#wxArray#" index="wxRow">
<!--- NOTE: Yay go CF8s implicit struct creation! --->
<cfset WXRow = {
city = trim(mid(wxRow,1,15)) , <!--- trim() will remove leading/trailing spaces --->
sky = trim(mid(wxRow,16,10)) ,
tmp = trim(mid(wxRow,26,4)) ,
dp = trim(mid(wxRow,30,4)) ,
rh = trim(mid(wxRow,34,3)) ,
wind = trim(mid(wxRow,37,10)) ,
pres = trim(mid(wxRow,47,6)) ,
rmks = trim(mid(wxRow,53,11))
}>
<!--- ArrayAppend() returns true/false, so this variable isn't used. --->
<cfset throwaway = ArrayAppend(newWXArray, WXRow)>
</cfloop>
<cfdump var="#newWXArray#">
Now you have an array of all the cities, and can pull the individual pieces out for the city you need.
What's the weather like in Liberty? <br>
<cfset whichRow = 0>
<cfloop from="1" to="#arrayLen(newWXArray)#" index="i">
<cfif newWXArray[i].CITY IS "LIBERTY">
<cfset whichRow = i>
</cfif>
</cfloop>
<cfoutput>
City >> #newWXArray[whichRow].CITY# <br>
Sky >> #newWXArray[whichRow].SKY# <br>
Temp >> #newWXArray[whichRow].TMP# <br>
DewPoint >> #newWXArray[whichRow].DP# <br>
Relative Humidity >> #newWXArray[whichRow].RH# <br>
Wind >> #newWXArray[whichRow].WIND# <br>
Pressure >> #newWXArray[whichRow].PRES# <br>
Remarks >> #newWXArray[whichRow].RMKS# <br>
</cfoutput>
Final Note:
I had forgotten how limited CF8 was. There is a lot of stuff you can do to make this MUCH easier if you are able to upgrade to a current version of ACF or Lucee.
Also, as I suggested, changing your link to pull the Text-Only version (https://forecast.weather.gov/product.php?site=CAE&issuedby=CAE&product=RWR&format=txt&version=1&glossary=1) will significantly reduce the amount of text you have to parse through.
My experience with white space in text data messing up conditional logic has been with trailing spaces but the principles are the same. When in doubt look at your data. Here is a simple example:
MyVar = 'Lgt Rain'; // two spaces between the words
if (MyVar == 'Lgt Rain'){ // one space between words
applicable code
}
else {
writeoutput(replace(MyVar, ' ', '-space-', 'all'));
}
Related
I'm able to get query's over a time span of say 1hr - in 15 minute increments...
I am just trying to stop displaying repetitive result when the Primary Key is the same.
ie: If something starts at 6:45am - and ends at 8:00am - I only want it to span the DIV once if the primary key (masterid) is the same. And then if something else is at 8am with a different primary key - to span that div time frame etc...
I am contemplating a cfloop or the like - checking that the mastered is either the same or different/
Thoughts on how to do this...
Query code working fine - as is my display code... Image included to give idea of what I'm trying to do.
<cfloop index="incr" from="0" to="#loopreps#">
<cfoutput>
Loopreps is thru the time spans of 15 mins...
<cfquery name="scht" datasource="#ds#">
Proper Query
</cfquery>
<cfif scht.recordcount is not 0>
<cfset mid = #scht.masterid#>
This is where I am lost to hold it to only 1 result when spanning time
Proper Display Across Div Height Span once if MasterID is same
</cfif>
</cfoutput>
</cfloop>
As noted in the comments, as a desktop database, MS Access is rather limited. Enterprise databases like SQL Server offer much greater capabilities for tasks like this, such as using CTE's.
However, just to offer another perspective, you could also use an auxiliary table of times, instead. (That was a common approach in SQL Server, prior to the advent of CTE's). You could easily populate a table with fifteen minute increments, between 00:00 to 23:45, using Mark's loop as a basis. Then simply JOIN to that table on the scheduled start and end times. (Access requires the extra parenthesis and derived table).
SELECT ti.IntervalTime
, s.StartTime
, s.EndTime
, s.AppointmentName
FROM TimeInterval ti LEFT JOIN
(
SELECT AppointmentName, StartTime, EndTime
FROM ScheduleTable
WHERE ScheduleDate = <cfqueryparam value="#someDate#" cfsqltype="cf_sql_timestamp">
) s
ON (
ti.IntervalTime >= s.StartTime AND
ti.IntervalTime <= s.EndTime
)
WHERE ti.IntervalTime >= <cfqueryparam value="#fromTime#" cfsqltype="cf_sql_timestamp">
AND ti.IntervalTime <= <cfqueryparam value="#toTime#" cfsqltype="cf_sql_timestamp">
ORDER BY ti.IntervalTime
The result will contain all of the intervals and appointments in one query, no need for looping. You can then output the results however you need.
IntervalTime | StartTime | EndTime | Appointment Name
06:00:00 | | |
06:15:00 | | |
06:30:00 | | |
06:45:00 | 06:45:00 | 08:00:00 | Edge
07:00:00 | 06:45:00 | 08:00:00 | Edge
07:15:00 | 06:45:00 | 08:00:00 | Edge
07:30:00 | 06:45:00 | 08:00:00 | Edge
....
You can loop over time increments directly using the CFLOOP tag. For example this code outputs each 15 minutes. You could combine a loop like this with a check (Q of a Q maybe) to extract availability.
<cfloop index="tm" from="8:00 AM" to="5:00 PM" step="#createTimespan(0,0,15,0)#">
<cfoutput> <li>#TimeFormat( tm, "h:mm TT" )#</li></cfoutput>
</cfloop>
Just keep in mind this is an ok solution for short iterations. If doing long iterations I would set that "step" attribute to a variable rather than calling a function directly. If really long I would probably choose something else. But for a couple days worth of increments it will work perfectly fine I think. See this post on Interesting loop for date and time. Good luck!
I usually put a garbage value before starting a loop.
<cfset CompareValue = "value that will never occur in real life">
<cfloop>
<cfif FieldToCheck is not CompareValue>
<cfset CompareValue = FieldToCheck>
more code
<cfelse>
appropriate code, maybe nothing
</cfif>
</cfloop>
I am trying to use a cent sign in my ColdFusion program. It appears to be ascii 155. The function Chr() only interprets values up to 127, although the documentation says otherwise. I found a clue in that I may need to enable high ascii characters in the ColdFusion administrator, but I could not find a place to do that. This codes works:
<cfset x = Chr(127)>
<cfoutput> this is what you get with #x# </cfoutput>
I get a nice box. But this returns only a blank:
<cfset x = Chr(155)>
<cfoutput> this is what you get with #x# </cfoutput>
How do I get Chr() working with higher numbers?
The "cent sign" is ¢, which is chr(162) (which works fine) or ¢ as a HTML entity.
If you want the › symbol then use chr(8250) or ›.
Looks like the standard american ascii chr that we are all used to, and coldfusion chr numbering do not match up.
According to the Livedocs (version 8)
ColdFusion MX: Changed Unicode support: ColdFusion supports the Java UCS-2 representation of Unicode characters, up to a value of 65535. (Earlier releases supported 1-255.)
If you look here, this blog shows some of CF's and the HTML equiv... so you can find some of them more easily.
cf and html entities
Out of interest, i made a simple loop, and thought i'd look through them, and there are plenty of chars... the hard part is finding the right one.
162 is a cent though, as stated in another answer, but this might help explain why.
<cfoutput>
<cfloop index="i" from="1" to="10000">
<pre>Chr #i# = #chr(i)#</pre>
</cfloop>
</cfoutput>
Java UCS-2 has lots of weird characters, as you can see here.
Some Sample output:
Chr 2922 = ୪
Chr 2923 = ୫
Chr 2924 = ୬
Chr 2925 = ୭
Chr 2926 = ୮
Chr 2927 = ୯
Chr 2928 = ୰
Chr 2929 = ୱ
Chr 3207 = ಇ
Chr 3208 = ಈ
Chr 3209 = ಉ
Chr 3210 = ಊ
Chr 3211 = ಋ
Chr 3212 = ಌ
I'm trying to format numbers so that 2 decimal places show up, unless it is a whole number - then I don't want a decimal point to show. I've tried 0.00, _.__, 9.99 and several combinations. Is there a mask for the numberFormat function that can get this result?
<cfif int(x) eq x>
#int(x)#
<cfelse>
#DecimalFormat(x)#
</cfif>
You could divide the variable by 1 and then the whole number is shown without a decimal place.
<cfset a = 5.00>
<cfset b = 5.55>
<cfoutput>#a/1#, #b/1#</cfoutput>
Output is 5, 5.55. Instead of 5.00, 5.55 if you don't divide by 1.
I do not think there is an existing function, but this rounding example might do the trick:
round(yourNumber * 100) / 100
EDIT:
As JasonM mentioned in the comments this will not produce two decimal places for numbers like 1.1.
Ok, I know this question is years old and my solution is dumb as hell but it worked for my needs:
#replace(dollarformat(list_price), '.00', '')#
I know this was dollarformat not number format, but the concept is the same.
LOL. If it's dumb and it works it's not dumb, right?
Still super gross. WTF Adobe?
#REReplace(REReplace(DecimalFormat(value), "0+$", "", "ALL"), "\.+$", "")#
credit: http://www.webveteran.com/blog/web-coding/coldfusion/trimming-a-decimal-with-coldfusion-regex/
I know it's been ages, but if you first do the Numberformat of the value, then Trim it, you will get the desired result ... NumberFormat makes it have trailing digits after the decimal - TRIM will eliminate the trailing decimals if they are just zeroes.
5.55 would result in 5.55 , 5.00 would result in 5 , 5.5 would result in 5.5
etc
I prefer my code as flat as a pancake and try to avoid conditionals whenever possible. So if you feel comfortable dropping down a level to Java you can use DecimalFormat to get the results you want.
<cfset n = JavaCast("double", 1.0) />
<cfset x = CreateObject("java", "java.text.DecimalFormat").init() />
<cfset x.applyPattern("##.##") />
<cfset y = x.format(n) />
The following one liner would also work.
<cfset y = CreateObject("java", "java.text.DecimalFormat").init( "##.##" ).format( JavaCast("double", 1.0) ) />
I'd use precisionEvaluate() + numberFormat() + replaceFirst(regex)
<cfscript>
numberFormat( precisionEvaluate( num ), '_.00' ).replaceFirst( '\.00$', '' );
</cfscript>
For example:
50.00 -> 50
0.00 -> 0
0.001 -> 0
0.006 -> 0.01
123.45 -> 123.45
4/3 -> 1.33
5.24596 -> 5.25
pi() -> 3.14
12345678901234567890 -> 12345678901234567000
reReplace(numberFormat(val, "__.00"), "\.00$", "")
I need to decrypt a base64 encoded binary in string format [0-9a-zA-Z+/]. Part of this string consists of the ivSalt, which is the first 16 Bytes, or 128bits. The rest is data; everything was encrypted using AES with 128 key and in 128 CBC blocks and PKCS7Padding.
First the string needs to converted to binary:
<cfset b64 = ToBinary(enc)/>
Then we create a java byte buffer:
<cfset objByteBuffer = CreateObject(
"java",
"java.nio.ByteBuffer") />
Then we initialize a buffer for the salt and a buffer for the data that needs to be decrypted.
<cfset objBufferA = objByteBuffer.Allocate(
JavaCast( "int", 16 )) />
<cfset objBufferB = objByteBuffer.Allocate(
JavaCast( "int", (Len(b64)-16) )) />
Then we fill the buffers with our bytes.
<cfset objBufferA.Put(
b64,
JavaCast( "int", 0 ),
JavaCast( "int", 16 )) />
<cfset objBufferB.Put(
b64,
JavaCast( "int", 16 ),
JavaCast( "int", (Len(b64)-16) )) />
<cfset ivStringBin = objBufferA.Array()/>
<cfset dataStringBin = objBufferB.Array()/>
Because the decrypt function takes a hexadecimal string we need to encode it to hex.
<!--- create byteArray output stream --->
<cfset baos = createObject("java", "java.io.ByteArrayOutputStream")>
<!--- write the byteArray stored in the DB to the output stream --->
<cfset baos.write(ivStringBin)>
<!--- convert binary content to text string --->
<cfset ivString=BinaryEncode(baos.toByteArray(),"hex")/>
<!--- create byteArray output stream --->
<cfset baos2 = createObject("java", "java.io.ByteArrayOutputStream")>
<!--- write the byteArray stored in the DB to the output stream --->
<cfset baos2.write(dataStringBin)>
<!--- convert binary content to text string --->
<cfset dataString=BinaryEncode(baos2.toByteArray(),"hex")/>
Should be:
<cfset dataString=BinaryEncode(baos2.toByteArray(),"base64")/>
Now I'm not sure what to do with the key, but it appears to be required to be in a hexadecimal string format.
<cfset key = BinaryEncode(ToBinary("{16 chars, [0-9a-zA-Z+/]}")/>
Should be:
<cfset key = "{32 chars, [0-9A-Z]}"/>
ColdFusion doesn't itself support PKCS7Padding with CBC, I get an unsupported provider error. So I go and install BouncyCastle and I found a wonderful ColdFusion example of how to decrypt with PKCS5Padding Un-encrypting / re-encrypting a ColdFusion encrypted string in PHP">here. I added it to my code but I need PKCS7Padding so I changed
var zbPadding = CreateObject('java', 'org.bouncycastle.crypto.paddings.ZeroBytePadding').init();
to
var zbPadding = CreateObject('java', 'org.bouncycastle.crypto.paddings.PKCS7Padding').init();
according to the Bouncy Castle docs .
With all this I get the error:
"Key length not 128/160/192/224/256 bits."
I will be trying off and on but I am completely stuck, I can't figure out what I am doing wrong.
Edit 1:
I got it working!
The dataString needed to be in base64 instead of hex.
The key, when converted to hex using coldFusion is 24 [0-9A-F] chars representing 24x4=96 bits which is 12 Bytes. It needs to be 16 Bytes, so somehow the BinaryEncode(ToBinary()) function doesn't do its job. So I used a string to hex tool to convert it and then subsequently got 32 chars.
Edit 2:
Also, to install Bouncy Castle I followed the bouncy castle installe instructions and downloaded jce from the bottom of the java downloads page.
I got it working!
The dataString needed to be in base64 instead of hex.
The key, when converted to hex using coldFusion is 24 [0-9A-F] chars representing 24x4=96 bits which is 12 Bytes. It needs to be 16 Bytes, so somehow the BinaryEncode(ToBinary()) function doesn't do its job. So I used a string to hex tool to convert it and then subsequently got 32 chars.
Edit 2: Also, to install Bouncy Castle I followed the bouncy castle installe instructions and downloaded jce from the bottom of the java downloads page.
I have a list of user comments stored in a database and I'm displaying 10 per page. On page load I need to dynamically render the appropriate amount of page numbers. At first I thought I would just get the total amount of comments and divide that by 10 to get the # of pages. That however doesn't work correctly. For example:
1. 1-10
2. 11-21
3. 22-32
4. 33-43
5. 44-54
6. 55-65
7. 66-76
So basically with my original math if I have 70 results I will have 7 pages, but if I have 71 results I get 8 pages, which obviously isn't correct. How can I fix this?
Here's my original code:
<cfset commentsNumber = getComments.recordcount / 10>
<cfloop from="1" to="#commentsNumber#" index="i" >
<cfoutput>
#i#
</cfoutput>
</cfloop>
Edit: I can't do math today :(
...if I have 71 results I get 8 pages, which obviously isn't correct.
10 results per page w/ 71 results is 8 pages. What's wrong?
If you want to be sure of your record paging in ColdFusion, you could use an open source library like Pagination.cfc. It handles all the math for you and gives you a customizable display.
hey correct you math first.. :) your example is wrong.
If you are showing 10 comments per page then it should be
1. 1-10
2. 11-20
3. 21-30
etc
By the way you can use CFGRID for paging... it's very simple..