|
Mailing Lists
|
Home /
Groups /
ColdFusion Talk (CF-Talk)
help with string manipulation (Find,Replace)
I've tried hard to find a solution to my problem butcf coder 03/29/04 06:31 A OK, just do something likeYalta Classen 03/29/04 07:19 A Many Thanks Yalta for your help. Your code is good but there it does handle the comments column properly if the comments column has the following data:cf coder 03/29/04 07:58 A Another way you could look at this is to check for the length of the total characters in the first line.Jas Panesar 05/18/04 12:34 P On CFMX onlyPascal Peters 03/29/04 08:55 A Thank you pascal, the code works just the way I want it to. here it is:cf coder 03/30/04 06:49 A #ParagraphFormat(variable)#Tangorre, Michael 03/30/04 07:23 A Actually, those 2 lines were meant to replace the cfif's too. You canPascal Peters 03/30/04 07:53 A This is for display in HTML, not in a textarea. The <p> tags would showPascal Peters 03/30/04 07:54 A can you show me how to do this?cf coder 03/30/04 08:24 A To do what? Show me the code of your textarea and any code manipulatingPascal Peters 03/30/04 08:39 A Hi Pascal, I'm really sorry for not getting back to you yesterday. I've been asked to work on something else.cf coder 03/31/04 10:55 A <cfsavecontent variable="str">Pascal Peters 03/31/04 02:21 P Sweet! You are a genius! I can never get my head round regular expressions.cf coder 04/01/04 05:57 A ^ start of stringPascal Peters 04/01/04 06:20 A thanks Pascal that explaination makes perfect sense and I understand it. Thanks again for all your help.cf coder 04/01/04 06:36 A Pascal or anybody who can help!cf coder 05/14/04 11:08 A <cfscript>Pascal Peters 05/17/04 04:40 A Hey Pascal, hope you're doing well buddy! I'm getting an error.cf coder 05/17/04 06:29 A I figured that out.. thankscf coder 05/17/04 06:58 A sorry for being such a pest... I forgot to add in my earlier post that the timestamp for all existing comments is in the format:cf coder 05/17/04 07:11 A <cfscript>Pascal Peters 05/17/04 07:33 A thanks Pascal! It doesn't quite work how I would like it to.cf coder 05/17/04 07:50 A Pascal, sorry again for being such a PEST. I really do apprecaite your help.cf coder 05/17/04 08:32 A <cfscript>Pascal Peters 05/17/04 10:18 A Pascal,Bartlett, Robert E. USNUNK NAVAIR 1490, 54-L4 05/17/04 10:40 A It's like a flat file. (a huge comment field in the DB).Pascal Peters 05/17/04 10:53 A My bad, I responded to Pascal earlier... Sorry about that.Bartlett, Robert E. USNUNK NAVAIR 1490, 54-L4 05/17/04 10:55 A Hi Robert,cf coder 05/17/04 11:12 A cf coder wrote:Stephen Moretti 05/18/04 06:40 A > thisLogLine = trim(ListGetAt(LogField,i));Stephen Moretti 05/18/04 06:45 A If your format isn't always the same (*** user timestamp *** OR ***Pascal Peters 05/17/04 11:09 A I'm off to home right now, but I'll send you the code in the morningPascal Peters 05/17/04 11:31 A Thanks Pascal. Sorry again for any inconvenience caused.cf coder 05/17/04 11:39 A ON CF5Pascal Peters 05/18/04 05:30 A Thanks Pascal, your script works just fine. Thanks again for your help, most appreciated.cf coder 05/18/04 08:10 A > You end up with a nice wee query of all the log entries for aPascal Peters 05/18/04 08:11 A I agree with Pascal, regexps are the most powerfull tools when it comes to parsing, however they are not easy to code. Pascal I was wondering if you could explain what your code is doing:cf coder 05/18/04 08:27 A Here you go:Pascal Peters 05/19/04 03:53 A thank you once again Pascal, I'll get my head stuck in the CFMX reference guidecf coder 05/19/04 05:54 A > You may want to read a bit about regexp. I heard good things about Ben'sDeanna Schneider 05/19/04 08:20 A I've tried hard to find a solution to my problem but have had no luck. I am pulling the data from the 'comments' column in a database table. The data in the comments column looks like this. "TEST - CLOSE CALL *** 10/28/2003 2:53:52 *** THIS IS A TEST- PLEASE CLOSE CALL *** 04/06/2003 12:33:5" I want to only display the first comment, in this case "TEST - CLOSE CALL". I am able to do this. Here is the code I've written to display the first comment. #Left(qResults.Slug,Find('#Chr(13)#',qResults.Slug))# The above code searches for a new line in the comment column and displays everything before the new line. The problem I'm having is looking for the first comment (top-most comment) when the data stored in the column begins with a new line " MOVE FOLDER *** 04/06/2003 13:41:47 *** blah, blah *** 04/06/2003 12:33:5" As shown in the above example, there a number of new line characters before the first comment ("Move Folder"). I don't know how to approach this problem, I want to replace all new line characters before the first occurance of a character between a-z. Can someone please show me how to do this please Cheers, cfcoder __________________________________ Do you Yahoo!? Yahoo! Finance Tax Center - File online. File on time. http://taxes.yahoo.com/filing.html OK, just do something like <cfset sTmp=REReplaceNoCase(qResults.Slug,'^[^a-z0-9_]*([a-z0-9_])','\1'> to get rid of all leading characters you do not want, and then use sTmp for you Find. Just a few remarks: '^[^a-z0-9_]*([a-z0-9_])' means First ^- Start at the start of the string only [] one of those inside, with the second ^ - one of those NOT inside * - repeated 0 to x times () take everything inside and remember it - for a back reference \1 later The () has to be used to make sure that all leading whitespace is removed (ad consequently, you need a back reference later) You might want to experiment using a different collection of excluded/included chars. There is for example \s for whitespace, \S for non-whitespace, but my experiments with those CF-specific character class definitions were never too lucky, so I prefer enumerating the characters I want/don't want. Yalta Many Thanks Yalta for your help. Your code is good but there it does handle the comments column properly if the comments column has the following data: *** 09/05/2002 18:46:21 *** Closing as no point to this log Hot Swap *** 17/04/2002 13:08:15 *** OK can ayone tell me where the Request for the replacement PC is. I want to display the string "Closing as no point to this log Hot Swap" whereas if I use your code, the string that's displayed is: " 09/05/2002 18:46:21 " This is my code: <cfif Find('#Chr(13)#',qResults.Slug)> <cfset tmp=REReplaceNoCase(qResults.Slug,'^[^a-z0-9_]*([a-z0-9_])','\1')> <cfif Find('***',tmp) and trim(Left(tmp,Find('***',tmp)-1)) neq ""> #trim(Left(tmp,Find('***',tmp)-1))# <cfelseif trim(Left(tmp,Find('#Chr(13)#',tmp))) neq ""> #trim(Left(tmp,Find('#Chr(13)#',tmp)))# <cfelse> #tmp# </cfif> </cfif> ----- Excess quoted text cut - see Original Post for more ----- > > You might want to experiment using a different collection of > excluded/included chars. There is for example \s for whitespace, \S > for non-whitespace, but my experiments with those CF-specific > character class definitions were never too lucky, so I prefer > enumerating the characters I want/don't want. > Yalta Another way you could look at this is to check for the length of the total characters in the first line. If it will never be less than 4, then you could wrap it with a conditional statement to check until it finds the first real line that is longer than 4 characters. On CFMX only // replaces whitespace and date/time before first comment str = REReplace(str,"^\s*([*]{3}.*?[*]{3})?\s*",""); // Replaces everything starting from next *** str = REReplace(str,"^(.*?)\s*[*]{3}.*$","\1"); NOT tested, I don't have CFMX running at the moment Pascal ----- Excess quoted text cut - see Original Post for more ----- Thank you pascal, the code works just the way I want it to. here it is: <cfif Find('#Chr(13)#',qResults.Slug)> <cfset tmp=REReplaceNoCase(qResults.Slug,'^[^a-z0-9_]*([a-z0-9_])','\1')> <cfif Find('***',tmp) and trim(Left(tmp,Find('***',tmp)-1)) neq ""> <cfset str = REReplace(qResults.Slug,"^\s*([*]{3}.*?[*]{3})?\s*","")> <cfset str = REReplace(str,"^(.*?)\s*[*]{3}.*$","\1")> #str# <cfelseif trim(Left(tmp,Find('#Chr(13)#',tmp))) neq ""> #trim(Left(tmp,Find('#Chr(13)#',tmp)))# <cfelse> #tmp# </cfif> </cfif> I need your help with something else. This is not related to my original query, but related. When the comment field data is displayed in a text area, it looses the new line character. Don't know why. Here is an example. MOVE FOLDER *** 04/06/2003 13:41:47 *** blah, blah *** 04/06/2003 2:33:5" When I want display it like this: MOVE FOLDER *** 04/06/2003 13:41:47 *** blah, blah *** 04/06/2003 12:33:5" Can you show me how to do this please. Best Regards, cfcoder ----- Excess quoted text cut - see Original Post for more ----- #ParagraphFormat(variable)# Mike > I need your help with something else. This is not related to > my original query, but related. When the comment field data > is displayed in a text area, it looses the new line > character. Don't know why. Here is an example. Actually, those 2 lines were meant to replace the cfif's too. You can replace the whole block by my code (but test it anyway!!). For your other problem, I see two possibilities: 1. You are using HTMLEditFormat() to display in the textarea. It replaces CR/LF. Just create a UDF that replaces &,<,>," and use that instead (be sure to replace & first). 2. There is no LF (chr(10)) in your code and that is why it doesn't show. THT Pascal ----- Excess quoted text cut - see Original Post for more ----- This is for display in HTML, not in a textarea. The <p> tags would show and everything would be on one line ----- Excess quoted text cut - see Original Post for more ----- can you show me how to do this? >This is for display in HTML, not in a textarea. The <p> tags would show >and everything would be on one line To do what? Show me the code of your textarea and any code manipulating the string you display in it and I will try to give you the solution Pascal ----- Excess quoted text cut - see Original Post for more ----- Hi Pascal, I'm really sorry for not getting back to you yesterday. I've been asked to work on something else. I'm trying to display the comment properly and need your help. I want to display the top most comment from the comments table. Here is an example. In the example below there are 2 comments *** 13/01/2003 09:47:06 TUser1 *** callno:1126 Some comment1 *** 13/01/2003 08:30:27 TUser2 *** Some Comment2 I want to display the top most comment. In this case *** 13/01/2003 09:47:06 TUser1 *** callno:1126 Some comment1 All comments have the ***, date time and user information "*** 13/01/2003 09:47:06 TUser1 ***" I would really apprecaite your help. Best Regards, cfcoder <cfsavecontent variable="str"> *** 13/01/2003 09:47:06 TUser1 *** callno:1126 Some comment1 *** 13/01/2003 08:30:27 TUser2 *** Some Comment2 </cfsavecontent> <cfscript> regexp = "^\s*([*]{3}.+?[*]{3}.+?)\s*(?:[*]{3}.*)?$"; str2 = REReplace(str,regexp,"\1"); </cfscript> <cfoutput><pre>#str2#</pre></cfoutput> This returns the first comment with the datetime & user info. If you want it without that info the regexp should be "^\s*[*]{3}.+?[*]{3}(.+?)\s*(?:[*]{3}.*)?$" Watch out for wrapping. There are no spaces in the regexp. Pascal ----- Excess quoted text cut - see Original Post for more ----- Sweet! You are a genius! I can never get my head round regular expressions. I don't have a clue what this is actually doing regexp = "^\s*([*]{3}.+?[*]{3}.+?)\s*(?:[*]{3}.*)?$"; str2 = REReplace(str,regexp,"\1"); Can you kindly explain it to me because I have to explain it to my colleague and not look like a fool. Thanks Pascal ----- Excess quoted text cut - see Original Post for more ----- ^ start of string \s* any number of whitespace (spaces, tabs, newlines,...) ( start group (for back reference) [*]{3} three stars .+? one or more characters (non greedy match: untill first match of what comes next) [*]{3} three stars .+? one or more characters (non greedy match: untill first match of what comes next) ) end group \s* any number of whitespace (spaces, tabs, newlines,...) (?:[*]{3}.*)? optional group not included in backreference: three stars followed by any number of characters $ end of string \1 backreference to match for first group ([*]{3}.+?[*]{3}.+?) Pascal PS If you don't understand the difference between greedy and non greedy matches, try doing the same on a string with 2 or more comments using .+ instead of .+? ----- Excess quoted text cut - see Original Post for more ----- thanks Pascal that explaination makes perfect sense and I understand it. Thanks again for all your help. Best Regards, cfcoder Pascal or anybody who can help! I'm in a similar problem again and need your help. I'm currently using the code provided by Pascal. The solution to which is mentioned above. I am pulling the data from the 'comments' column in a database table. The data in the comments column looks like this. *** User1 10/28/2003 2:53:52 *** THIS IS A TEST *** User 2 04/06/2003 13:41:47 *** blah, blah I want to read everything that's between the *** ie *** User 1 10/28/2003 2:53:52 *** and display it like this: <span class="time">User 1 | 14/4/2004 15:58:15</span> THIS IS A TEST Can somebody please show me how to do this using regular expressions? Many thanks cf coder <cfscript> stTmp = REFind("[*]{3}[[:space:]]+([^*]+)[[:space:]]+[*]{3}",str,1,true); info = Mid(str,stTmp.pos[2],stTmp.len(2); </cfscript> <cfoutput><span class="time">#info#</span></cfoutput> ----- Excess quoted text cut - see Original Post for more ----- Hey Pascal, hope you're doing well buddy! I'm getting an error. The selected method len was not found. Either there are no methods with the specified method name and argument types, or the method len is overloaded with arguments types that ColdFusion can't decipher reliably. If this is a Java object and you verified that the method exists, you may need to use the javacast function to reduce ambiguity. Any idea why? I figured that out.. thanks <cfscript> stTmp = REFind("[*]{3}[[:space:]]+([^*]+)[[:space:]]+[*]{3}",str,1,true); info = Mid(str,stTmp.pos[2],stTmp.len[2]); </cfscript> <span class="timestamp">#info#</span> the above code works however I was wondering if you could do me another favour. At the minute you are searching for the "***". Would it be possible to come up with a pattern that finds the three stars, username, date and time? ex: *** User1 10/28/2003 2:53:52 *** Its just so its fool proof. My concern is if the column contains three stars somewhere else in the comments then this code would fail. Are you with me? sorry for being such a pest... I forgot to add in my earlier post that the timestamp for all existing comments is in the format: *** 10/28/2003 2:53:52 User1 *** and the timestamp for new comments is: *** User1 10/28/2003 2:53:52 *** Can you also show me how to display all existing timestamps in the above format Many many thanks in advance. <cfscript> stTmp = REFind("[*]{3}([^*]+)([0-9]{1,2}/[0-9]{1,2}/[0-9]{4})[[:space:]]+([0-9]{ 1,2}:[0-9]{1,2}:[0-9]{1,2})([^*]+)[*]{3}",str,1,true); user1 = Mid(str,stTmp.pos[2],stTmp.len[2]); date = Mid(str,stTmp.pos[3],stTmp.len[3]); time = Mid(str,stTmp.pos[4],stTmp.len[4]); user2 = Mid(str,stTmp.pos[5],stTmp.len[5]); if(len(trim(user1))) user = trim(user1); else if(len(trim(user2))) user = trim(user2); else user = ""; </cfscript> <span class="timestamp">#user# #date# #time#</span> It's not full proof, but it should work. ----- Excess quoted text cut - see Original Post for more ----- thanks Pascal! It doesn't quite work how I would like it to. EX: *** 08/12/2003 20:33:31 EDWARI31 *** You code displays the above timestamp like this: 0 8/12/2003 20:33:31 Where as I would like it to be displayed like this: EDWARI31 08/12/2003 20:33:31 I dumped stTmp <cfdump var="#stTmp#">. This is what it returns struct LEN array 1 38 2 2 3 9 4 8 5 11 POS array 1 1 2 4 3 6 4 17 5 25 Pascal, sorry again for being such a PEST. I really do apprecaite your help. There can be more than one occurance of the timestamp in the comment column. Ex: *** 05/12/2003 09:52:10 USER1 *** closing if fixed - awaitng response from User2 *** 04/12/2003 18:55:18 USER2 *** Have been there, however user was on air shortly after, will try again in a bit. *** 04/12/2003 18:13:22 USER3 *** Roger that *** 04/12/2003 18:05:01 USER4 *** closed Can you please add code in your script to handle this and display all timestamps correctly Many thanks again cfcoder ----- Excess quoted text cut - see Original Post for more ----- <cfscript> start = 1; aLog = ArrayNew(1); while(true){ stTmp = REFind("[*]{3}([^*]*[[:space:]])([0-9]{1,2}/[0-9]{1,2}/[0-9]{4})[[:space :]]+([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})([[:space:]][^*]*)[*]{3}",str,star t,true); if(stTmp.pos[1]){ stLog = StructNew(); stLog = StructNew(); user1 = Mid(str,stTmp.pos[2],stTmp.len[2]); stLog.date = Mid(str,stTmp.pos[3],stTmp.len[3]); stLog.time = Mid(str,stTmp.pos[4],stTmp.len[4]); user2 = Mid(str,stTmp.pos[5],stTmp.len[5]); if(len(trim(user1))) stLog.user = trim(user1); else if(len(trim(user2))) stLog.user = trim(user2); else stLog.user = ""; stLog.text = ""; if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Mid(str,start,stTmp.pos[1]-start); } ArrayAppend(aLog,stLog); start = stTmp.pos[1]+stTmp.len[1]; } else{ if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Trim(Mid(str,start,Len(str)-start)); } break; } } </cfscript> <cfoutput> <cfloop from="1" to="#ArrayLen(aLog)#" index="i"> <div class="timestamp">#aLog[i].user# #aLog[i].date# #aLog[i].time#</div> <pre>#aLog[i].text#</pre> </cfloop> </cfoutput> ----- Excess quoted text cut - see Original Post for more ----- You are a GENIUS man! That code rocks, I wouldn't know how to do this without your help. You are a star. Just one small problem, the comments column sometimes doesn't store the timestamp. I went through your code. The while condition in the above mentioned situation would be false so the code in the else part would be executed. if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Trim(Mid(str,start,Len(str2)-start)); } The above condition would be false. I added a 'else' condition and want to assign 'str' to aLog[ArrayLen(aLog)].text. something like this: if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Trim(Mid(str,start,Len(str2)-start)); } else { 'What should I be doing here?' } break; Many thanks again! Pascal, I may have missed the answer to this question, but is the content that we are looking at a query record set (multiple records), or is it from like a flat file, where the content is just appended? It seems like all of these solutions are overly complex. It seems like such a simple problem to resolve. Thanks, Robert <cfscript> start = 1; aLog = ArrayNew(1); while(true){ stTmp = REFind("[*]{3}([^*]*[[:space:]])([0-9]{1,2}/[0-9]{1,2}/[0-9]{4})[[:space :]]+([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})([[:space:]][^*]*)[*]{3}",str,star t,true); if(stTmp.pos[1]){ stLog = StructNew(); stLog = StructNew(); user1 = Mid(str,stTmp.pos[2],stTmp.len[2]); stLog.date = Mid(str,stTmp.pos[3],stTmp.len[3]); stLog.time = Mid(str,stTmp.pos[4],stTmp.len[4]); user2 = Mid(str,stTmp.pos[5],stTmp.len[5]); if(len(trim(user1))) stLog.user = trim(user1); else if(len(trim(user2))) stLog.user = trim(user2); else stLog.user = ""; stLog.text = ""; if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Mid(str,start,stTmp.pos[1]-start); } ArrayAppend(aLog,stLog); start = stTmp.pos[1]+stTmp.len[1]; } else{ if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Trim(Mid(str,start,Len(str)-start)); } break; } } </cfscript> <cfoutput> <cfloop from="1" to="#ArrayLen(aLog)#" index="i"> <div class="timestamp">#aLog[i].user# #aLog[i].date# #aLog[i].time#</div> <pre>#aLog[i].text#</pre> </cfloop> </cfoutput> ----- Excess quoted text cut - see Original Post for more ----- It's like a flat file. (a huge comment field in the DB). Storing the comments in a related table would have made his life easier, but I don't think he can change the way the data is stored. ----- Excess quoted text cut - see Original Post for more ----- My bad, I responded to Pascal earlier... Sorry about that. CFCODER: You have shown your data two ways, and this impacts any solution that is presented: Latest: *** 05/12/2003 09:52:10 USER1 *** closing if fixed - awaitng response from User2 *** 04/12/2003 18:55:18 USER2 *** Have been there, however user was on air shortly after, will try again in a bit. *** 04/12/2003 18:13:22 USER3 *** Roger that *** 04/12/2003 18:05:01 USER4 *** closed Originally: *** User1 10/28/2003 2:53:52 *** THIS IS A TEST *** User 2 04/06/2003 13:41:47 *** blah, blah So which is it? Also, I may have missed this answer, but it seems to me that the solution is to drop the separate data elements into their own fields in the database IN THE FIRST PLACE. That way they can be queried out, or barring that solution, change the code that writes each entry to include delimiters e.g. *** User 2|04/06/2003|13:41:47***blah, blah And use CR/LF between fields to separate records... I'm sorry if this doesn't help, but the fact is you are dealing with output that sorely needs to be reformatted to make it easier to process. You shouldn't need anything major to pull it apart. Thanks, Robert P.S. What are the rules for the data that you are pulling apart now? e.g. 3 asterisks, space date, 2 spaces, time, 2 spaces, username, 2 spaces, 3 asterisks, comment, cr/lf, cr/lf 3 asterisks, space date, 2 spaces, time, 2 spaces, username, 2 spaces, 3 asterisks, comment, cr/lf, cr/lf etc... Pascal, sorry again for being such a PEST. I really do apprecaite your help. There can be more than one occurance of the timestamp in the comment column. Ex: *** 05/12/2003 09:52:10 USER1 *** closing if fixed - awaitng response from User2 *** 04/12/2003 18:55:18 USER2 *** Have been there, however user was on air shortly after, will try again in a bit. *** 04/12/2003 18:13:22 USER3 *** Roger that *** 04/12/2003 18:05:01 USER4 *** closed Can you please add code in your script to handle this and display all timestamps correctly Many thanks again cfcoder ----- Excess quoted text cut - see Original Post for more ----- Hi Robert, apologies for causing any confusion. I was asked to present the data stored in the database table column in a certain way. Historically data stored in this column is as under: timestamp comments EX: *** 05/12/2003 09:52:10 USER1 *** closing if fixed - awaitng response from User2 I was asked to get rid of the stars and reorder the timestamp to something like this: USER1 05/12/2003 09:52:10 (Username, Date, Time) All comments (timestamps) added henceforth will be added in this fashion. I hope this gives you a better understanding. The solution Pascal provided does just that and it does the job for me. Best Regards, cfcoder ----- Excess quoted text cut - see Original Post for more ----- > *** 04/12/2003 18:55:18 USER2 *** > Have been there, however user was on air shortly after, will try again > in a bit. > > *** 04/12/2003 18:13:22 USER3 *** > Roger that > > *** 04/12/2003 18:05:01 USER4 *** > closed > > Originally: > > *** User1 10/28/2003 2:53:52 *** > > THIS IS A TEST > > *** User 2 04/06/2003 13:41:47 *** ----- Excess quoted text cut - see Original Post for more ----- > *** 04/12/2003 18:55:18 USER2 *** > Have been there, however user was on air shortly after, will try again > in a bit. > > *** 04/12/2003 18:13:22 USER3 *** > Roger that > ----- Excess quoted text cut - see Original Post for more ----- cf coder wrote: ----- Excess quoted text cut - see Original Post for more ----- Ummm.... This thread has been going on and on and I can't help but feel that this is overcomplicated this somewhat... Your comment is a string with a number of lines in it. Your date/time stamp is denoted by being started and finished with 3 asterisks. Wouldn't this be simpler? <cfscript> //create new query for this record's Comment/LogField entry thisLogQuery = QueryNew(); QueryAddColumn(thisLogQuery,"UserID"); QueryAddColumn(thisLogQuery,"logDate"); QueryAddColumn(thisLogQuery,"logTime"); QueryAddColumn(thisLogQuery,"Comment"); for (i=1;i lTE ListLen(LogField,chr(13)); i=i+1) { thisLogLine = trim(ListGetAt(LogField,i)); if (ListFirst(thisLogLine," ") EQ "***") { // new date stamp, new row QueryAddRow(thisLogQuery); if (IsDate(ListGetAt(thisLogLine,2," ")){ // Check for old format with date first QuerySetCell(thisLogQuery,"logDate",ListGetAt(thisLogLine,2," ")); QuerySetCell(thisLogQuery,"logTime",ListGetAt(thisLogLine,3," ")); QuerySetCell(thisLogQuery,"UserID",ListGetAt(thisLogLine,4," ")); } else { // otherwise use new format QuerySetCell(thisLogQuery,"UserID",ListGetAt(thisLogLine,2," ")); QuerySetCell(thisLogQuery,"logDate",ListGetAt(thisLogLine,3," ")); QuerySetCell(thisLogQuery,"logTime",ListGetAt(thisLogLine,4," ")); } } else QuerySetCell(thisLogQuery,"Comment",thisLogQuery.Comment[recordcount]&chr(13)&thisLogLine); } </cfscript> You end up with a nice wee query of all the log entries for a record, new and old user/date/time stamps are handled, handles comments with multiple lines, it'll be easier to display the contents of the query, it should work in both CF5 and CFMX and anyone looking at it later can read the code! FOOT NOTE: I just typed this in off the top of my head. I haven't run the code, or checked it in anyway. You may need to tweak it or it might need minor debugging.. Regards Stephen > thisLogLine = trim(ListGetAt(LogField,i)); Whoops.... Immediately spotted an error : thisLogLine = trim(ListGetAt(LogField,i,chr(13))); Forgot to put the list delimiter in to get one line out of the comments/LogField. Stephen If your format isn't always the same (*** user timestamp *** OR *** timestamp user ***) you can't use my code. You need to do it in a different way. I can help if you want, but if you keep changing the specs it's not very easy. Also, remind me what version you are on. I'm writing CF5 regexp for the moment, but this is easier in CFMX. Pascal ----- Excess quoted text cut - see Original Post for more ----- sorry Pascal, my bad. The format is not always the same, there may be few comments in the database without the timestamp. All comments added when I build the functionality will not have the *** user timestamp ***. I have CFMX installed on the server. Best regards, cfcoder ----- Excess quoted text cut - see Original Post for more ----- I'm off to home right now, but I'll send you the code in the morning (for me GMT+2) ----- Excess quoted text cut - see Original Post for more ----- Thanks Pascal. Sorry again for any inconvenience caused. Best regards cfcoder >I'm off to home right now, but I'll send you the code in the morning >(for me GMT+2) ON CF5 <cfscript> start = 1; aLog = ArrayNew(1); commentRegexp = "[*]{3}[[:space:]]+([^*]*)[[:space:]]+[*]{3}"; timestampRegexp = "[0-9]{1,2}/[0-9]{2}/[0-9]{4}[[:space:]]+[0-9]{2}:[0-9]{2}:[0-9]{2}"; while(true){ stTmp = REFind(commentRegexp,str,start,true); if(stTmp.pos[1]){ stLog = StructNew(); header = Mid(str,stTmp.pos[2],stTmp.len[2]); stTmp2 = REFind(timestampRegexp,header,1,true); if(stTmp2.pos[1]){ stLog.user = Trim(Removechars(header,stTmp2.pos[1],stTmp2.len[1])); stLog.timestamp = Mid(header,stTmp2.pos[1],stTmp2.len[1]); } else{ stLog.user = Trim(header); stLog.timestamp = ""; } stLog.text = ""; if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Mid(str,start,stTmp.pos[1]-start); } ArrayAppend(aLog,stLog); start = stTmp.pos[1]+stTmp.len[1]; } else{ if(ArrayLen(aLog)){ aLog[ArrayLen(aLog)].text = Trim(Mid(str,start,Len(str)-start)); } break; } } </cfscript> <cfoutput> <cfloop from="1" to="#ArrayLen(aLog)#" index="i"> <div class="timestamp">#aLog[i].user# #aLog[i].timestamp#</div> <pre>#aLog[i].text#</pre> </cfloop> </cfoutput> ON CFMX <cfscript> start = 1; aLog = ArrayNew(1); commentRegexp = "[*]{3}\s+(.*?)\s+[*]{3}(.*?)(?=([*]{3}\s+.*?\s+[*]{3})|$)"; timestampRegexp = "\d{1,2}/\d{2}/\d{4}\s+\d{2}:\d{2}:\d{2}"; while(true){ stTmp = REFind(commentRegexp,str,start,true); if(stTmp.pos[1]){ stLog = StructNew(); header = Mid(str,stTmp.pos[2],stTmp.len[2]); stTmp2 = REFind(timestampRegexp,header,1,true); if(stTmp2.pos[1]){ stLog.user = Trim(Removechars(header,stTmp2.pos[1],stTmp2.len[1])); stLog.timestamp = Mid(header,stTmp2.pos[1],stTmp2.len[1]); } else{ stLog.user = Trim(header); stLog.timestamp = ""; } stLog.text = Mid(str,stTmp.pos[3],stTmp.len[3]); ArrayAppend(aLog,stLog); start = stTmp.pos[1]+stTmp.len[1]; } else{ break; } } </cfscript> The script on CF5 breaks if you have * between *** *** The script on CFMX doesn't > Thanks Pascal. Sorry again for any inconvenience caused. Thanks Pascal, your script works just fine. Thanks again for your help, most appreciated. Best regards, cfcoder > You end up with a nice wee query of all the log entries for a Do you mean that queries are easier than arrays of structs. I hardly see a difference. Creating a query takes more work, but displaying an array takes more work too. So I think it's a question of personal prefference (or what you need to do with it later). > record, new and old user/date/time stamps are handled, Your code handels old and new comments, but not comments without datestamp. It also doesn't handle user names with spaces in it. > handles comments with multiple lines, it'll be easier to > display the contents of the query, it should work in both CF5 > and CFMX and anyone looking at it later can read the code! The code for cf5 will work in cfmx too, but do you imply that you can't write cfmx specific code and use new features because you want everything to be cf5 compattible? I admit that the code lacked comment, but I have a lot of work at the moment and was writing this quickly to help him out. Are you implying that we shouldn't use regexp, because other developers my not understand it when they read it later? I think regexps is one of the most powerfull tools when it comes to parsing. Just because some people don't understand it, doesn't mean we shouldn't use it. I agree with Pascal, regexps are the most powerfull tools when it comes to parsing, however they are not easy to code. Pascal I was wondering if you could explain what your code is doing: commentRegexp = "[*]{3}\s+(.*?)\s+[*]{3}(.*?)(?=([*]{3}\s+.*?\s+[*]{3})|$)"; timestampRegexp = "\d{1,2}/\d{2}/\d{4}\s+\d{2}:\d{2}:\d{2}"; Many thanks Here you go: [*]{3} ==> three stars \s+ ==> one or more space characters (tab, space, newline, return) (.*?) ==> any number of characters (non greedy: smallest string to match the regexp) \s+ ==> idem [*]{3} ==> idem (.*?) ==> idem (?= ==> positive lookahead (has to be followed by, doesn't remember the group for backreferencing) ([*]{3}\s+.*?\s+[*]{3}) ==> explained before | ==> OR $ ==> end of string ) ==> end positive lookahead \d{1,2} ==> one or two digits / ==> slash \d{2} ==> two digits And so on You may want to read a bit about regexp. I heard good things about Ben's book. I've ordered it myself (to use and recommend in my classes), but it has a hard time getting to Belgium so I haven't read it yet. There is also http://www.regular-expressions.info/ as an online resource. Pascal Peters Certified ColdFusion MX Advanced Developer Macromedia Certified Instructor LR Technologies Av. E. De Mot, 19 1000 BRUSSELS, BELGIUM ----- Excess quoted text cut - see Original Post for more ----- thank you once again Pascal, I'll get my head stuck in the CFMX reference guide. > You may want to read a bit about regexp. I heard good things about Ben's > book. I've ordered it myself (to use and recommend in my classes), but > it has a hard time getting to Belgium so I haven't read it yet. There is > also http://www.regular-expressions.info/ as an online resource. > I've got this book and was following along nicely until the look ahead. (I haven't read that far in the book yet.) In fact, I had a similar solution going, based on what I'd learned in the book so far. I was having problems with where to say "don't be greedy," though, and was ending up with everything between the first and and the last set of "***"s. (Point being, I second the recommendation for the book.)
|
February 09, 2012
|
Latest Fusion Authority Articles
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||