Search code examples
stringcoldfusiondelimiter

Get string with listGetAt delimiter


I have this string supplier_id ~|(~ '3422' ~)|~supplier_name ~|(~ 'WD Ltd.' ~)|~project_personnel ~|(~ 'Yaya Toure (temp)' ~)|~lt_project_code ~|(~ '013-7718321' ~)|~ id ~|(~ '668'

and I need to get content inside ~|(~data~)|~. I use listGetAt with delimiter. The problem is some data inside delimiter contain bracket ( which ruin the search. For example with Yaya Toure (temp) that contain bracket.

<cfoutput>
<cfset test = "supplier_id ~|(~ '3422' ~)|~supplier_name ~|(~ 'WD Ltd.' ~)|~project_personnel ~|(~ 'Yaya Toure (temp)' ~)|~lt_project_code ~|(~ '013-7718321' ~)|~ id ~|(~ '668'">

#test#
<cfset count_column = ListLen(test, "~)|~")>

<cfset column_name = ''>
<cfloop index="i" from="1" to=8 >
    <cfif i mod 2 EQ 0>
        <cfset column_name = ListAppend(column_name,listGetAt(test, i, "~|(~~)|~" ),",")>
    </cfif>
</cfloop>

<br>
<br>

Result : #column_name#
</cfoutput>

Output : Result : '3422' , 'WD Ltd.' , 'Yaya Toure ,'

My expected result is : '3422' , 'WD Ltd.' , 'Yaya Toure (temp)' , '013-7718321'. It will work if I removed (temp) from the string. Please assist me with this and thanks in advance.

iddle : https://cffiddle.org/app/file?filepath=ab77d723-1b04-46d6-8d80-fb765b881768/5c8c9eed-a16a-4f3a-b40b-fd7479fdc5ea/dae87d17-2826-4c63-b54c-55a57a8e4398.cfm


Solution

  • Option 1: Use a CF list function that supports multi-character delimiters, like listToArray.

    <cfscript>
        // split on first delimiter get "name->value" string
        nameValuePairs = test.listToArray("~)|~" , false, true);
    
        columnValues = [];
        nameValuePairs.each(function(pair, index) {
            // split on second delimiter to extract value
            local.data = pair.listToArray("~|(~", false, true);
            columnValues.append( local.data[ 2 ] );
        });
        
        writeDump( "Result 1: "& columnValues.toList() );    
    </cfscript>
    

    Option 2: If you can identify a single character that's never present within the values, perhaps a non-printable character, just replace the existing delimiters, and loop as usual.

    <cfscript>
          // 31 == Unit separator        
          delim     = chr(31);
          newString = test.replace( "~)|~", delim, "all")
                        .replace( "~|(~", delim, "all");
    
          columnValues = [];
          newString.listToArray( delim ).each(function( elem, index) {
              if (index mod 2 == 0) {
                  columnValues.append( elem );
              }
          });
        
          WriteOutput( "<br>Result 2: "&  columnValues.toList()  );        
    </cfscript>   
    
     
    

    TryCF Examples

    Update

    problem though for this string supp~|(~lier_isd ~|(~ '3422' ~)|~supplier_name ~|(~ 'WD Ltd.' ~)|~project_personnel ~|(~ 'Yaya Toure (temp)' ~)|~lt_project_code ~|(~ '013-7718321' ~)|~ id ~|(~ '668' I was expecting lier_isd ~|(~ '3422', 'WD Ltd.', 'Yaya Toure (temp)', '013-7718321'

    The initial string appeared to use the format name ~|(~ value ~)|~. However, if the value itself can contain one of the list delimiters ~|(~, you won't be able to use list functions, because the function can't differentiate between when ~|(~ is acting as a delimiter and when it's part of a value. You'll need to use a regex instead. That's not my forte, but something like this should work

    TryCF Example

      values = [];
      // Find groups of "~|(~ value ~)|~"
      matches = reMatch( "~\|\(~(.+?)(?=~\)\|~)", test);
      matches.each( function(item, index) {
        // remove text up to and including the first "~|(~"
        local.str = reReplace( item, ".*?~\|\(~", "");
        values.append( local.str );
      });
      
      WriteOutput( "Result 1: "& values.toList() );    
    

    Explanation

         ~        Find tilde "~"
         \|       Find pipe "|"
         \(       Find open parenthesis "("
         ~        Find tilde "~"
         
         (.+?)    One ore more characters, non-greedy
         
         (?=      Followed by (Non-capturing lookahead) 
         ~        tilde "~"
         \)       close parenthesis "("
         \|       pipe "|"
         ~        tilde "~"
         )        End lookahead
         
         .*?      Zero or more characters
         ~        Find tilde "~"
         \|       Find pipe "|"
         \(       Find open parenthesis "("
         ~        Find tilde "~"