I'm pulling my hair out over this one! I'm using ColdFusion to generate .rtf files like the one below for printing Avery mailing labels. For some reason, a space appears before each name in the first column, but only after the first row. This has me stumped because I've looked at the source being generated and don't see an extra character before the name, even though when I open the .rtf in a text editor I can delete the character manually to fix this. Can anyone tell me why that extra space is there? You can download the actual .rtf file at this URL:
http://www.bitmojo.com/Avery-Label-Test.rtf
Well I guess I can't post images...feel free to ask for a link if you need clarification.
Adding this here since it was too long for a comment:
I'm using the CF_AVERYRTF.CFM custom tag from over ten years ago...hasn't been updated since to my knowledge. I'll edit my question to add the code that actually generates and saves out the RTF. It uses cfsavecontent, cfscript and writeoutput to create the variable that gets saved to disk as the .rtf file, and when I cfdump that variable before the .rtf gets written to disk I don't see any extra characters before the names, but when I open the .rtf file source in my code editor I see a space before each name, and when I open the .rtf in the text editor on my mac I only see spaces before the names in the first column after the first row...that's what's driving me crazy, seeing different things depending on where and how I'm looking at the data...that's why I posted the example file, so someone could take a look and at least verify what I'm seeing. Here's an image of the symptom as it appears on my Mac (spaces circled)
screen shot http://www.bitmojo.com/Avery-Label-Screen-Shot.png
Also here's the code that generates the data:
<cfsavecontent variable="ThisTag.GeneratedRTF">
<cfscript>
// open RTF document with header information
writeOutput("{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\fswiss Arial;}{\f1\fswiss Helvetica;}{\f2\fswiss Impact;}{\f3\froman Times New Roman;}}");
writeOutput("{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red255\green255\blue255;}");
writeOutput("{\info{\title VFIVE Label Generator (#request.rtfLabels.labeltitle# Output)}{\author cf_averyRTF $Revision: 1.17 $}{\operator cf_averyRTF resides at http://rtf.vfive.com}{\*\company VFIVE (http://www.vfive.com)}{\creatim\yr#Year(now())#\mo#Month(now())#\dy#Day(now())#\hr#Hour(now())#\min#Minute(now())#}{\version1}{\edmins0}{\nofpages1}{\nofwords0}{\nofchars0}{\nofcharsws0}{\vern1000}}\paperw#request.rtfLabels.paperw#\paperh#request.rtfLabels.paperh#\margl#request.rtfLabels.margl#\margr#request.rtfLabels.margr#\margt#request.rtfLabels.margt#\margb#request.rtfLabels.margb#");
if (Attributes.landscape)
{
writeOutput("\landscape");
}
writeOutput("\gutter#request.rtfLabels.gutter# \widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\horzdoc \jexpand\viewkind1\viewscale#request.rtfLabels.viewscale#\nolnhtadjtbl \fet0\sectd \linex#request.rtfLabels.linex#\sectdefaultcl");
// loop over each row in the dataset
for (ii = 1; ii LTE arrayLen(thisTag.assocAttribs); ii = ii + 1)
{
// if this is the first cell of a row, create the row (like <tr>)
if (NOT ((ii + request.rtfLabels.columns - 1) MOD request.rtfLabels.columns))
{
// output the <tr>-like row start, cellBoundary
writeOutput("\trowd \trrh#request.rtfLabels.trrhcell#\trkeep" & cellBoundary);
// output row setup (align, indent, etc)
writeOutput(" \pard\plain \q#request.rtfLabels.textalign# \li#request.rtfLabels.li#\ri#request.rtfLabels.ri#\widctlpar\intbl\faauto \f#request.rtfLabels.defaultfontface#\fs20\lang1033\langfe1033");
}
// output each individual cell header (like <td>)
writeOutput("{\#request.rtfLabels.bold#\fs#request.rtfLabels.defaultfontsize#\f#request.rtfLabels.defaultfontface# ");
// output barcode on top if appropriate
if (len(trim(thisTag.assocAttribs[ii].zipCode)) AND thisTag.assocAttribs[ii].barPos EQ "top")
{
writeOutput("{\field\flddirty{\*\fldinst { BARCODE }{\lang1024\langfe1024\noproof #ThisTag.AssocAttribs[ii].zipcode#}{\\u }}{\fldrslt }}\par");
}
// loop over the lines of content in this cell
for (jj = 1; jj LTE arrayLen(ThisTag.AssocAttribs[ii].arrCell); jj = jj + 1)
{
// content to be displayed?
if (len(trim(thisTag.assocAttribs[ii].arrCell[jj].content)) OR NOT thisTag.assocAttribs[ii].stripBlankLines)
{
// are we bolding this line of content?
if (thisTag.assocAttribs[ii].arrCell[jj].bold)
{
writeOutput("\b");
}
else
{
writeOutput("\b0");
}
writeOutput("\fs#ThisTag.AssocAttribs[ii].arrCell[jj].fs#\f#ThisTag.AssocAttribs[ii].arrCell[jj].f##ThisTag.AssocAttribs[ii].arrCell[jj].content#");
if (jj LT arrayLen(ThisTag.AssocAttribs[ii].arrCell))
{
writeOutput("\par");
}
}
}
// close out cell (like a </td>)
writeOutput("}{\fs#request.rtfLabels.defaultfontsize#\f#request.rtfLabels.defaultfontface# ");
// output barcode on bottom if appropriate
if (len(trim(thisTag.assocAttribs[ii].zipCode)) AND thisTag.assocAttribs[ii].barPos EQ "bottom")
{
writeOutput(" {\field\flddirty{\*\fldinst { BARCODE }{\lang1024\langfe1024\noproof #ThisTag.AssocAttribs[ii].zipcode#}{\\u }}{\fldrslt }}");
}
// prepare to close this cell </td>
writeOutput("\cell } ");
// close this cell out like a </td>
if (ii MOD request.rtfLabels.columns)
{
writeOutput(" \pard \q#request.rtfLabels.textalign# \li#request.rtfLabels.li#\ri#request.rtfLabels.ri#\widctlpar\intbl\faauto {\cell }");
}
else
{
writeOutput("\pard\plain \q#request.rtfLabels.textalign# \li#request.rtfLabels.li#\ri#request.rtfLabels.ri#\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright \fs#request.rtfLabels.defaultfontsize#\f#request.rtfLabels.defaultfontface#\lang1033\langfe1033");
}
// if this is the last cell of a row, end it (like a </tr>) --->
if (NOT (ii MOD request.rtfLabels.columns))
{
// start close: output code + cellCloser + " \row }"
writeOutput("\pard\plain \q#request.rtfLabels.textalign# \li#request.rtfLabels.li#\ri#request.rtfLabels.ri#\widctlpar\intbl\aspalpha\aspnum\faauto\adjustright \fs#request.rtfLabels.defaultfontsize#\f#request.rtfLabels.defaultfontface#\lang1033\langfe1033 {\trowd \trrh#request.rtfLabels.trrhcell#\trkeep " & cellCloser & " \row }#chr(13)##chr(10)#");
// add an extra spacer row?
if (request.rtfLabels.useSpacer)
{
// output complete spacerRow as defined above
writeOutput(spacerRow);
}
}
// end of outer for loop
}
// close out document
writeOutput("\pard \q#request.rtfLabels.textalign# \li#request.rtfLabels.li#\ri#request.rtfLabels.ri#\widctlpar\aspalpha\aspnum\faauto\adjustright { \par }{ \par }}");
</cfscript>
</cfsavecontent>
We can't say much about this without seeing code. Added to what #Miguel-F said, if you're using any of your own functions in this process, have they got output="false" specified?
CF has a nasty habit of haemorrhaging whitespace (like from your source code's indentation) unless you specifically control it. This doesn't cause a problem (other than bloat) for rendered HTML as the HTML spec says it ought to be ignored, so the browser does so. This is not the case for other file formats.
It will almost certainly be your code's white space bleeding through.
One fairly easy way of dealing with this is to use CFScript rather than tags, wherever possible (which is reasonable advice as a matter of course anyhow, do keep your code clear and concise).
UPDATE
If you are using a custom tag, make sure you have <cfsilent> tags around the call to it, and around everything within it which emits anything. Custom tags are terrible for emitting spurious whitespace.
This resolved itself now that I've upgraded to ColdFusion 2016, so I'm going to write it off as a bug in ColdFusion that was solved by Adobe.
Related
Goal: I have a bunch of keywords I'd like to categorise automatically based on topic parameters I set. Categories that match must be in the same column so the keyword data can be filtered.
e.g. If I have "Puppies" as a first topic, it shouldn't appear as a secondary or third topic otherwise the data cannot be filtered as needed.
Example Data: https://docs.google.com/spreadsheets/d/1TWYepApOtWDlwoTP8zkaflD7AoxD_LZ4PxssSpFlrWQ/edit?usp=sharing
Video: https://drive.google.com/file/d/11T5hhyestKRY4GpuwC7RF6tx-xQudNok/view?usp=sharing
Parameters Tab: I will add words in columns D-F that change based on the keyword data set and there will often be hundreds, if not thousands, of options for larger data sets.
Categories Tab: I'd like to have a formula or script that goes down the columns D-F in Parameters and fills in a corresponding value (in Categories! columns D-F respectively) based on partial match with column B or C (makes no difference to me if there's a delimiter like a space or not. Final data sheet should only have one of these columns though).
Things I've Tried:
I've tried a bunch of things. Nested IF formula with regexmatch works but seems clunky.
e.g. this formula in Categories! column D
=IF(REGEXMATCH($B2,LOWER(Parameters!$D$3)),Parameters!$D$3,IF(REGEXMATCH($B2,LOWER(Parameters!$D$4)),Parameters!$D$4,""))
I nested more statements changing out to the next cell in Parameters!D column (as in , manually adding $D$5, $D$6 etc) but this seems inefficient for a list thousands of words long. e.g. third topic will get very long once all dog breed types are added.
Any tips?
Functionality I haven't worked out:
if a string in Categories B or C contains more than one topic in the parameters I set out, is there a way I can have the first 2 to show instead of just the first one?
e.g. Cell A14 in Categories, how can I get a formula/automation to add both "Akita" & "German Shepherd" into the third topic? Concatenation with a CHAR(10) to add to new line is ideal format here. There will be other keywords that won't have both in there in which case these values will just show up individually.
Since this data set has a bunch of mixed breeds and all breeds are added as a third topic, it would be great to differentiate interest in mixes vs pure breeds without confusion.
Any ideas will be greatly appreciated! Also, I'm open to variations in layout and functionality of the spreadsheet in case you have a more creative solution. I just care about efficiently automating a tedious task!!
Try using custom function:
To create custom function:
1.Create or open a spreadsheet in Google Sheets.
2.Select the menu item Tools > Script editor.
3.Delete any code in the script editor and copy and paste the code below into the script editor.
4.At the top, click Save save.
To use custom function:
1.Click the cell where you want to use the function.
2.Type an equals sign (=) followed by the function name and any input value — for example, =DOUBLE(A1) — and press Enter.
3.The cell will momentarily display Loading..., then return the result.
Code:
function matchTopic(p, str) {
var params = p.flat(); //Convert 2d array into 1d
var buildRegex = params.map(i => '(' + i + ')').join('|'); //convert array into series of capturing groups. Example (Dog)|(Puppies)
var regex = new RegExp(buildRegex,"gi");
var results = str.match(regex);
if(results){
// The for loops below will convert the first character of each word to Uppercase
for(var i = 0 ; i < results.length ; i++){
var words = results[i].split(" ");
for (let j = 0; j < words.length; j++) {
words[j] = words[j][0].toUpperCase() + words[j].substr(1);
}
results[i] = words.join(" ");
}
return results.join(","); //return with comma separator
}else{
return ""; //return blank if result is null
}
}
Example Usage:
Parameters:
First Topic:
Second Topic:
Third Topic:
Reference:
Custom Functions
I've added a new sheet ("Erik Help") with separate formulas (highlighted in green currently) for each of your keyword columns. They are each essentially the same except for specific column references, so I'll include only the "First Topic" formula here:
=ArrayFormula({"First Topic";IF(A2:A="",,IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))) & IFERROR(CHAR(10)®EXEXTRACT(REGEXREPLACE(LOWER(B2:B&C2:C),IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))),""),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))))})
This formula first creates the header (which can be changed within the formula itself as you like).
The opening IF condition leaves any row in the results column blank if the corresponding cell in Column A of that row is also blank.
JOIN is used to form a concatenated string of all keywords separated by the pipe symbol, which REGEXEXTRACT interprets as OR.
IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))) will attempt to extract any of the keywords from each concatenated string in Columns B and C. If none is found, IFERROR will return null.
Then a second-round attempt is made:
& IFERROR(CHAR(10)®EXEXTRACT(REGEXREPLACE(LOWER(B2:B&C2:C),IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))),""),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>"")))))
Only this time, REGEXREPLACE is used to replace the results of the first round with null, thus eliminating them from being found in round two. This will cause any second listing from the JOIN clause to be found, if one exists. Otherwise, IFERROR again returns null for round two.
CHAR(10) is the new-line character.
I've written each of the three formulas to return up to two results for each keyword column. If that is not your intention for "First Topic" and "Second Topic" (i.e., if you only wanted a maximum of one result for each of those columns), just select and delete the entire round-two portion of the formula shown above from the formula in each of those columns.
Getting stuck on how to read and pretty up these values from a multiline cell via arrayformula.
Im using regex as preceding line can vary.
just formulas please, no custom code
The first column looks like a set of these:
```
[config]
name = the_name
texture = blah.dds
cost = 1000
[effect0]
value = 1000
type = ATTR_A
[effect1]
value = 8
type = ATTR_B
[feature0]
name = feature_blah
[components]
0 = comp_one,1
[resources]
res_one = 1
res_five = 1
res_four = 1
<br/>
Where to be useful elsewhere, at minimum it needs each [tag] set ([effect\d], [feature\d], ect) to be in one column each, for example the 'effects' column would look like:
ATTR_A:1000,ATTR_B:8
and so on.
Desired output can also be seen in the included spreadsheet
<br/>
<b>Here is the example spreadsheet:</b>
https://docs.google.com/spreadsheets/d/1arMaaT56S_STTvRr2OxCINTyF-VvZ95Pm3mljju8Cxw/edit?usp=sharing
**Current REGEXREPLACE**
Kinda works, finds each 'type' and 'value' great, just cant figure out how to extract just that from the rest, tried capture (and non-capturing) groups before and after but didnt work
=ARRAYFORMULA(REGEXREPLACE($A3:$A,"[\n.][effect\d][\n.](.)\n(.)","1:$1 2:$2"))
**Current SUBSTITUTE + REGEXEXTRACT + REGEXREPLACE**
A different approach entirely, also kinda works, longer form though and left with having to parse the values out of that string, where got stuck again. Idea was to use this to simplify, then regexreplace like above. Getting stuck removing content around the final matches though, and if can do that then above approach is fine too.
// First ran a substitute
=ARRAYFORMULA(SUBSTITUTE(SUBSTITUTE($A3:$A,char(10),";"),";;",char(10)))
// Then variation of this (gave up on single line 'effect/d' so broke it up to try and get it working)
=ARRAYFORMULA(IF(A3:A<>"",IFERROR(REGEXEXTRACT(A3:A,"(?m)^(?:[effect0]);(.)$")&";;")&""&IFERROR(REGEXEXTRACT(A3:A,"(?m)^(?:[effect1]);(.)$")&";;")&""&IFERROR(REGEXEXTRACT(A3:A,"(?m)^(?:[effect2]);(.)$")&";;"),""))
// Then use regexreplace like above
=ARRAYFORMULA(REGEXREPLACE($B3:$B,"value = (.);type = (.);;","1:$1 2:$2"))
**--EDIT--**
Also, as my updated 'Desired Output' sheet shows (see timestamped comment below), bonus kudos if you can also extract just the values of matching 'type's to those extra columns (see spreadsheet).
All good if you cant though, just realized would need that too for lookups.
**--END OF EDIT--**
<br/>
Ive tried dozens of things, discarding each in turn, had a quick look in version history to grab out two promising attempts and shared them in separate sheets.
One of these also used SUBSTITUTE to simplify input column, im happy for a solution using either RAW or the SUBSTITUTE results.
<br/>
**Potentially Useful links:**
https://github.com/google/re2/wiki/Syntax
<br/>
<b>Just some more words:</b>
I also have looked at dozens of stackoverflow and google support pages, so tried both REGEXEXTRACT and REGEXREPLACE, both promising but missing that final tweak. And i tried dozens of tweaks already on both.
Any help would be great, and hopefully help others in future since examples with spreadsheets are great since every new REGEX seems to be a new adventure ;)
<br/>
P.S. if we can think of better title for OP, please say in comment or your answer :)
paste in B3:
=ARRAYFORMULA(SUBSTITUTE(TRIM(TRANSPOSE(QUERY(TRANSPOSE(
IF(C3:E<>"", C2:E2&":"&C3:E, )),,999^99))), " ", ", "))
paste in C3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT($A3:$A, "(\d+)\ntype = "&C2)))
paste in D3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT($A3:$A, "(\d+)\ntype = "&D2)))
paste in E3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT($A3:$A, "(\d+)\ntype = "&E2)))
paste in F3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT(A3:A, "\[feature\d+\]\nname = (.*)")))
paste in G3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT(A3:A, "\[components\]\n\d+ = (.*)")))
paste in H3:
=ARRAYFORMULA(IFNA(REGEXREPLACE(INDEX(SPLIT(REGEXEXTRACT(
REGEXREPLACE(A3:A, "\n", ", "), "\[resources\], (.*)"), "["),,1), ", , $", )))
spreadsheet demo
This was a fun exercise. :-)
Caveat first: I have added some "input data". Examples:
[feature1]
name = feature_active_spoiler2
[components]
0 = spoiler,1
1 = spoilerA, 2
So the output has "extra" output.
See the tab ADW's Solution.
I'm trying to use autohotkey to gather a chuck of data from a website and then click a certain spot on the website depending on what the text is. I'm able to get it to actually pick up the value but when it comes to the if statement it won't seem to process and yields no error message. Here is a quick sample of my code, there is about 20 if statement values so for brevity sake I've only included a few of the values.
GuessesLeft = 20
Errorcount = 0
;triple click and copy text making a variable out of the clipboard
;while (GuessesLeft!=0) part of future while loop
;{ part of future while loop
click 927,349
click 927,349
click 927,349
Send ^c
GetValue = %Clipboard%
if ( GetValue = "Frontal boss")
{
click 955,485
Guessesleft -= 1
}
else if ( GetValue = "Supraorbital Ridge")
{
click 955,571
Guessesleft -= 1
}
;....ETC
else
{
Errorcount += 1
}
;} part of future while loop
Any tips on what I might be doing wrong. Ideally I'd use a case statement but AHK doesn't seem to have them.
Wait a second -- you are triple clicking to highlight a full paragraph and copying that to the clipboard and checking to see if the entirety of the copied portion is the words in the if statement, right? And your words in the copied portion have quotes around them? Probably you will have to trim off any trailing spaces and/or returns:
GetValue = % Trim(Clipboard)
If that doesn't work, you may even have to shorten the length of the copied text by an arbitrary character or two:
GetValue = % SubStr(Clipboard, 1, (StrLen(Clipboard)-2))
Now, if I am wrong, and what you are really looking for is the words from the if statement wherever they may be in a longer paragraph -- and they are not surrounded by quotes, then you will want something like:
IfInString, Clipboard, Frontal boss
Or, if the quotes ARE there,
IfInString, Clipboard, "Frontal boss"
Hth,
I have a list of products and I am trying to alternate the colour between each product (grey, white, grey, white, and so on). I understand how to use colour formatting based on a condition such as the following link: example followed. However I dont know how to get it to look at the previous line on the report and check whether it holds the same product name. If it does, then colour the row the same colour, else the alternate colour.
I've setup an example report in the application: Application 67666 - Colour Row by Product example. I have two products in the report so I'm trying to get 3 grey lines and then 3 white lines, if I had more products it would then go back to grey and so on.
Link:apex.oracle.com
workspace: apps2
user: user
password: DynamicAction2
Please could I be directed in the right direction, JavaScript and Dynamic Actions shout out to me as in the example link however its looking at the previous row which is getting me all stuck.
I can't think of another solution than javascript really. There is possibly using lag in the sql, but only to use it to determine where the row color should change. You could use the value of the column in a html expression of a column and put it in a class, but you still need to iterate over it with javascript anyway. So it seems less fiddly to just use javascript.
Inline CSS:
table.report-standard tr.normalRow td{
background-color: green;
}
table.report-standard tr.altRow td{
background-color: red;
}
This will override the default style, but you will need to tune this to your demands. For example, the color change on :hover of the row. I prefer steering the style through assigning classes and then define the rules in css than to directly assign css through javascript (which would place it in style tags, ugh).
Dynamic action: change row colour
After Refresh, Region, Product Report
True action: execute javascript code, fire on page load checked
$('td[headers="PRODUCT"]', this.triggeringElement).each(function(){
var lCurrRow = $(this).closest('tr'),
lPrevRow = lCurrRow.prev(),
lPrevVal = lPrevRow.find('td[headers="PRODUCT"]').text();
console.log(lPrevVal + ' - ' + $(this).text());
//if value on previous row differs from the that on the current row
//then change the class
//if the value didnt change, then use the same class as the previous row
if ( lPrevVal != $(this).text() ){
if ( lPrevRow.hasClass('normalRow') ){
lCurrRow.addClass('altRow');
} else {
lCurrRow.addClass('normalRow');
};
} else {
if ( lPrevRow.hasClass('normalRow') ){
lCurrRow.addClass('normalRow');
} else {
lCurrRow.addClass('altRow');
};
};
})
Check your solution on apex.oracle.com, I implemented it there.
I have a bunch of cells whose font size I'd like to tweak if their content is overflowing, until it all fits. I'd like to write a macro to do this, unless there's a conditional formatting or other formulaic way of doing it. Is there a property that tells whether a cell is overflowing? If so, what is it?
'open office 3
'get current document
oDoc = ThisComponent
' get first work sheet
oSheet = oDoc.getSheets().getByIndex(0)
'first cell in the work sheet
Cell = oSheet.getCellByPosition(0, 0)
MsgBox Cell.CharHeight
Happy Coading :))