How to use keep_after_last in Freemarker template - freemarker

I have the below code and i want to keep only last string or text e.g. ABC G56, so i want to keep only G56 after space so i am using keep_after_last in freemarker.
<td>${value?keep_after_last(" ")}</td>
but i am getting errors:
caused by: freemarker.core.parseexception: error on line 57, column 46, in template .ftl found keep_after_last, expecting one of: date, is_directive, parent, js_string, j_string, replace, uncap_first, float, right_pad, is_transform, number, datetime, node_type, split, is_hash, trim, children, has_content, is_sequence, xml, html, ancestors, new, last, byte, double, left_pad, sort, matches, capitalize, contains, eval, lower_case, size, web_safe, is_date, is_string, word_list, seq_last_index_of, node_namespace, string, keys, values, seq_index_of, chunk, sort_by, is_collection, long, starts_with, substring, index_of, default, root, is_boolean, floor, last_index_of, ceiling, if_exists, c, chop_linebreak, is_macro, rtf, upper_case, length, node_name, is_indexable, groups, reverse, cap_first, is_node, int, url, is_hash_ex, xhtml, ends_with, round, is_enumerable, interpret, is_method, namespace, exists, short, seq_contains, time, first, is_number in .ftl

Looks like your FreeMarker version is too old. ?keep_after_last was added in 2.3.22 (see https://freemarker.apache.org/docs/ref_builtins_string.html#ref_builtin_keep_after_last).
If you are not sure which version you are using, you can output it using ${.version} (see https://freemarker.apache.org/docs/ref_specvar.html).

Related

NIFI: Unable to extract two values from a list during each iteration over a loop

I would like to retrieve large SQL dump between date ranges. For the same, I constructed a loop over a date list, which intends to extract adjacent fields. Unfortunately, in my case, it doesnt work as planned.
Following is my flow:
Replace Text: Takes flowfile content date list as all_first_dates
Initialize Count:
While Loop:
Get first and adjacent dates:
However, on seeing the queue, I get the first and second as this:
Whereas, I desired as 2016-01-01 and 2016-01-02 for first and second respectively on my first iteration and so on.
check the description of the getDelimitedField function and it's parameters:
Description: Parses the Subject as a delimited line of text and returns just a single field from that delimited text.
Arguments:
index: The index of the field to return. A value of 1 will return the first field, a value of 2 will return the second field, and so on.
delimiter: Optional argument that provides the character to use as a field separator. If not specified, a comma will be used. This value must be exactly 1 character.
...
you are not passing the second parameter, so the coma used to split the subject, and you got the whole subject as one element in result.

string size limit input cin.get() and getline()

In this project the user can type in a text(maximum 140 characters).
so for this limitation I once used getline():
string text;
getline(cin, text);
text = text.substr(1, 140);
but in this case the result of cout << text << endl; is an empty string.
so I used cin.get() like:
cin.get(text, 140);
this time I get this error: no matching function for call to ‘std::basic_istream::get(std::__cxx11::string&, int)’
note that I have included <iostream>
so the question is how can I fix this why is this happening?
Your first approach is sound with one correction - you need to use
text = text.substr(0, 140);
instead of text = text.substr(1, 140);. Containers (which includes a string) in C/C++ start with index 0 and you are requesting the string to be trimmed from position 1. This is perfectly fine, but if the string happens to be only one character long, calling text.substr(1, 140); will not necessarily cause the program to crash, but will not end up in the desired output either.
According to this source, substr will throw an out of range exception if called with starting position larger than string length. In case of a one character string, position 1 would be equal to string length, but the return value is not meaningful (in fact, it may even be an undefined behavior but I cannot find a confirmation of this statement - in yours and my case, calling it returns an empty string). I recommend you test it yourself in the interactive coding section following the link above.
Your second approach tried to pass a string to a function that expected C-style character arrays. Again, more can be found here. Like the error said, the compiler couldn't find a matching function because the argument was a string and not the char array. Some functions will perform a conversion of string to char, but this is not the case here. You could convert the string to char array yourself, as for instance described in this post, but the first approach is much more in line with C++ practices.
Last note - currently you're only reading a single line of input, I assume you will want to change that.

Freemarker: Output comma separated list as an array

I have a table that has a field that contains a comma separated list of order IDs. What I am trying to do is output each of those IDs separately so that I can use them to look up their corresponding order details in another table.
Does anyone know of a good way to do this?
So far I have tried:
<#data Alerts_test_table as alerts_test>
<#filter
CUSTOMER_ID_=CONTACTS_LIST.CUSTOMER_ID_1>
<#fields AD_ID_LIST>
<#assign seq = ['${alerts_test.AD_ID_LIST}']>
<#list seq?chunk(1) as row><#list row as cell>
${cell}
</#list> </#list>
</#data>
But this just outputs it as a line of text.
Let's say you have comma separated ID-s in idsString, and you want to iterate though the ID-s one by one. Then:
Data-model (with http://try.freemarker.org/ syntax):
idsString = "11, 22, 33"
Template:
<#list idsString?split(r'\s*,\s*', 'r') as idString>
${idString}
</#list>
However, in the template you have posted I see many strange things, so some ideas/pointers:
Be sure that alerts_test.AD_ID_LIST is indeed a String, not a List that you can list directly, without ?split-ing. If it's a String, then '${alerts_test.AD_ID_LIST}' is ultimately the same as alerts_test.AD_ID_LIST. In general, you never need an empty string literal and an ${} in it. It's not useful (but sometimes harmful, as it converts non-string values to string).
?chunk(1) is not useful. The point of ?chunk is to slice a list to smaller lists, but if those smaller lists are to be 1 long, then you might as well just list the items of the original list.
There are no such directives as #data and #filter. Is this some forked FreeMarker version?
If the ID is a number that you need to pass to some API that expects a number, then you will have to convert it to number like idString?number.

Why is there a comma in this Golang struct creation?

I have a struct:
type nameSorter struct {
names []Name
by func(s1, s2 *Name) bool
Which is used in this method. What is going on with that comma? If I remove it there is a syntax error.
func (by By) Sort(names []Name) {
sorter := &nameSorter{
names: names,
by: by, //why does there have to be a comma here?
}
sort.Sort(sorter)
Also, the code below works perfectly fine and seems to be more clear.
func (by By) Sort(names []Name) {
sorter := &nameSorter{names, by}
sort.Sort(sorter)
For more context this code is part of a series of declarations for sorting of a custom type that looks like this:
By(lastNameSort).Sort(Names)
This is how go works, and go is strict with things like comma and parentheses.
The good thing about this notion is that when adding or deleting a line, it does not affect other line. Suppose the last comma can be omitted, if you want to add a field after it, you have to add the comma back.
See this post: https://dave.cheney.net/2014/10/04/that-trailing-comma.
From https://golang.org/doc/effective_go.html#semicolons:
the lexer uses a simple rule to insert semicolons automatically as it scans, so the input text is mostly free of them
In other words, the programmer is unburdened from using semicolons, but Go still uses them under the hood, prior to compilation.
Semicolons are inserted after the:
last token before a newline is an identifier (which includes words like int and float64), a basic literal such as a number or string constant, or one of the tokens break continue fallthrough return ++ -- ) }
Thus, without a comma, the lexer would insert a semicolon and cause a syntax error:
&nameSorter{
names: names,
by: by; // semicolon inserted after identifier, syntax error due to unclosed braces
}

Ruby: Optimizing storage for holding a huge number of strings, some of them duplicates

I have a text file with two columns. The values in the first column ("key") are all different, the values in the second column - these strings have a length between 10 and approximately 200 - have some duplicates. The number of duplicates varies. Some strings - especially the longer ones - don't have any duplicate, while others might have 20 duplicate occurancies.
key1 valueX
key2 valueY
key3 valueX
key4 valueZ
I would like to represent this data as a hash. Because of the large number of keys and the existence of duplicate values, I am wondering, whether some method of sharing common strings would be helpful.
The data in the file is kind of "constant", i.e. I can put effort (in time of space) to preprocess it in a suitable way, as long as it is accessed efficiently, once it is entered my application.
I will now outline an algorithm, where I believe this would solve the problem. My question is, whether the algorithm is sound, respectively whether it could be improved. Also, I would like to know whether using freeze on the strings would provide an additional optimization:
In a separated preprocessing process, I find out which strings values are indeed duplicate, and I annotate the data accordingly (i.e. create a third column in the file), in that all occurances of a repeated string except the first occurance, have a pointer to the first occurance:
key1 valueX
key2 valueY
key3 valueX key1
key4 valueZ
When I read in my application the data into memory (line by line), I use this annotation, to create a pointer to the original string, instead of allocating a new one:
if columns.size == 3
myHash[columns[0]] = columns[1] # First occurance of the string
else
myHash[columns[0]] = myHash[columns[2]].dup # Subsequent occurances
end
Will this achieve my goal? Can it be done any better?
One way you could do this is using symbols.
["a", "b", "c", "a", "d", "c"].each do |c|
puts c.intern.object_id
end
417768 #a
313128 #b
312328 #c
417768 #a
433128 #d
312328 #c
Note how c got the same value.
You can turn a string into a symbol with the intern method. If you intern an equal string you should get the same symbol out, like a flyweight pattern.
If you save the symbol in your hash you'll just have each string a single time. When it's time to use the symbol just call .to_s on the symbol and you'll get the string back. (Not sure how the to_s works, it may do creation work on each call.) Another idea would be to cache strings your self, ie have an integer to string cache hash and just put the integer key in your data structures. When you need the string you can look it up.

Resources