I've searched google and Stackoverflow but I just can't find an answer to my question.
I'm currently using Jaspersoft Studio 5.6.2 final and I'm trying to get a custom function to show up in my Expression Editor, but what ever I try I just cannot get the Category and function to show.
I started following the tutorial on https://community.jaspersoft.com/wiki/jaspersoft-studio-expression-editor-how-extend-it-and-contribute-your-own-functions-part-2-0. Generating all the necesarry files using the Functions Librry wizard (using File > New > Other > Jaspersoft Studio > Functions Library) and creating the function itself was easy.
The way the *.properties files are supposed to be configured is not very clear in the tutorial so I've also looked at http://jasperreports.sourceforge.net/sample.reference/functions/index.html#functions, after making adjustments to the properties file the custom function and category are still not showing
I've tried testing my code directly inside Jaspersoft, exporting it to a jar file, creating the jar file in another Eclipse and restarting Jaspersoft Studio. Nothing works.
Below is are the contents of my files.
The category class
package net.sf.jasperreports.functions.custom;
import net.sf.jasperreports.functions.annotations.FunctionCategory;
// I've also tried #FunctionCategory("Able")
#FunctionCategory()
public final class Able {
}
The class containing the function
package net.sf.jasperreports.functions.custom;
import net.sf.jasperreports.functions.annotations.Function;
import net.sf.jasperreports.functions.annotations.FunctionCategories;
import net.sf.jasperreports.functions.annotations.FunctionParameter;
import net.sf.jasperreports.functions.annotations.FunctionParameters;
import net.sf.jasperreports.functions.standard.TextCategory;
#FunctionCategories({ Able.class, TextCategory.class })
public final class AbleFunctions
{
/**
* Returns a barcode the custom font IDAutomationSHI25M will understand based on the page number
* and whether or not the current pagenumber is the lastpage
* #param pagenumber
* #param lastpage
* #return
*/
#Function("CREATE_BARCODE")
#FunctionParameters({
#FunctionParameter("pagenumber"),
#FunctionParameter("lastpage")})
public static String CREATE_BARCODE(Integer pagenumber, boolean lastpage)
{
String[] barcodeArray = {"!","\"", "#", "$", "%", "&", "(", ")", "*", "+", ",", "-", ".","/",
"0", "1", "2", "3", "4", "5", "6", "7", "8","9", ":", ";", "<", "=", ">", "?", "#",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
"R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^","_", "`","a", "b",
"c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "┼", "ã", "Ã", "╚", "╔", "╩"};
String onePage = barcodeArray[1] + barcodeArray[1];
String middlePagePrefix = barcodeArray[0];
String lastPagePrefix = barcodeArray[10];
// There are a couple of specific conditions that will generate a specific outcome.
// Checking these conditions first
if (pagenumber == 1 && lastpage) {
return onePage;
} else if (pagenumber > 1 && lastpage) {
return lastPagePrefix + barcodeArray[pagenumber];
} else {
return middlePagePrefix + barcodeArray[pagenumber];
}
}
}
jasperreports_messages.properties file
net.sf.jasperreports.functions.custom.Able.CREATE_BARCODE.description = Provide the current pagenumber and a boolean property telling if this is the lastpage and this method will return a string that can be turned in a barcode
net.sf.jasperreports.functions.custom.Able.CREATE_BARCODE.lastpage.description = A boolean value telling if the current page number belongs to the lastpage or not
net.sf.jasperreports.functions.custom.Able.CREATE_BARCODE.lastpage.name = lastpage
net.sf.jasperreports.functions.custom.Able.CREATE_BARCODE.name = CREATE_BARCODE
net.sf.jasperreports.functions.custom.Able.CREATE_BARCODE.pagenumber.description = The current page number
net.sf.jasperreports.functions.custom.Able.CREATE_BARCODE.pagenumber.name = pagenumber
net.sf.jasperreports.functions.custom.Able.description = Custom Able functions for Jasperreports
net.sf.jasperreports.functions.custom.Able.name = Able
jasperreports_extension.properties
net.sf.jasperreports.extension.registry.factory.functions=net.sf.jasperreports.functions.FunctionsRegistryFactory
net.sf.jasperreports.extension.functions.ablefunctions=eu.able.functions.AbleFunctions
As you can see in the AbleFunctions class I've also tried to add the function to the existing TextCategory class, but this also has no effect.
Does anybody have a clue what the problem could be? This is already taking me days without any succes so any help would be great!
This seems to be an old bug fixed with the latest version of the Community Edition: https://community.jaspersoft.com/questions/848371/custom-functions
Related
In my app I have a data pull from Firebase. I have a UITableViewController and would like to insert in a row a text from within the app. The data pull would be like this (please excuse the bad example but I cannot go into too much detail ..)
The original data pull:
Row 1: abc
Row 2: def
Row 3: ghi
Row 4: jkl
Row 5: mno
What I would like to achieve:
Row 1: abc
Row 2: def
Row 3: text from the app
Row 4: ghi
Row 5: jkl
Row 6: text from the app
Row 7: mno
How can I achieve this? I was trying to do something like this in cellForRowAt
if indexPath.row % 3 == 0 {
cell.text = "custom text"
}
But this is replacing every 3rd rows content. I would like to put a row in between, so to speak.
You can modify your server data with local data.
var serverData = ["a","b","c","d","e","f","g","h","i","j","k","l","m"]
let localAppData = ["1","2","3","4","5","6","7","8","9","10"]
var modified = [String]()
var counter = 0
for index in 1...serverData.count {
let value = serverData[index - 1]
if index % 3 == 0 && index != 0 {
if counter < localAppData.count {
modified.append(localAppData[counter])
}else{
modified.append(value)
}
counter += 1
}else{
modified.append(value)
}
}
serverData.removeAll()
serverData.append(contentsOf: modified)
print(serverData) //["a", "b", "1", "d", "e", "2", "g", "h", "3", "j", "k", "4", "m"]
if counter < localAppData.count {
// Appeds the remain local data to your serverData
serverData.append(contentsOf: localAppData[counter...localAppData.count-1])
}
print(serverData) //["a", "b", "1", "d", "e", "2", "g", "h", "3", "j", "k", "4", "m", "5", "6", "7", "8", "9", "10"]
Note: After modification you have to reload the tableView
You can update the datasource by inserting the value at 3rd position and use that datasource in cellforrowat
var a = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
var temp = a
for (ind, _) in a.enumerated() {
if ind % 3 == 0 && ind != 0 {
temp.insert("current text", at: ind)
}
}
print(temp) // Prints ["a", "b", "c", "current text", "d", "e", "current text", "f", "g", "h", "i"]
I am trying to alphabetically sort an array of non-English strings which contain a number of special Unicode characters. I can create a CharacterSet sequence which contains the desired lexicographic sort order.
Is there an approach in Swift5 to performing this type of customized sort?
I believe I saw such a function some years back, but a pretty exhaustive search today failed to turn anything up.
Any pointers would be appreciated!
As a simple implementation of matt's cosorting comment:
// You have `t` twice in your string; I've removed the first one.
let alphabet = "ꜢjiyꜤwbpfmnRrlhḥḫẖzsšqkgtṯdḏ "
// Map characters to their location in the string as integers
let order = Dictionary(uniqueKeysWithValues: zip(alphabet, 0...))
// Make the alphabet backwards as a test string
let string = alphabet.reversed()
// This sorts unknown characters at the end. Or you could throw instead.
let sorted = string.sorted { order[$0] ?? .max < order[$1] ?? .max }
print(sorted)
Rather than building your own “non-English” sorting, you might consider localized comparison. E.g.:
let strings = ["a", "á", "ä", "b", "c", "d", "e", "é", "f", "r", "s", "ß", "t"]
let result1 = strings.sorted()
print(result1) // ["a", "b", "c", "d", "e", "f", "r", "s", "t", "ß", "á", "ä", "é"]
let result2 = strings.sorted {
$0.localizedCaseInsensitiveCompare($1) == .orderedAscending
}
print(result2) // ["a", "á", "ä", "b", "c", "d", "e", "é", "f", "r", "s", "ß", "t"]
let locale = Locale(identifier: "sv")
let result3 = strings.sorted {
$0.compare($1, options: .caseInsensitive, locale: locale) == .orderedAscending
}
print(result3) // ["a", "á", "b", "c", "d", "e", "é", "f", "r", "s", "ß", "t", "ä"]
And a non-Latin example:
let strings = ["あ", "か", "さ", "た", "い", "き", "し", "ち", "う", "く", "す", "つ", "ア", "カ", "サ", "タ", "イ", "キ", "シ", "チ", "ウ", "ク", "ス", "ツ", "が", "ぎ"]
let result4 = strings.sorted {
$0.localizedCaseInsensitiveCompare($1) == .orderedAscending
}
print(result4) // ["あ", "ア", "い", "イ", "う", "ウ", "か", "カ", "が", "き", "キ", "ぎ", "く", "ク", "さ", "サ", "し", "シ", "す", "ス", "た", "タ", "ち", "チ", "つ", "ツ"]
Documentation for the string method addingPercentEncoding(withAllowedCharacters:):
Returns a new string made from the receiver by replacing all characters not in the specified set with percent-encoded characters.
The predefined set CharacterSet.alphanumerics says:
Returns a character set containing the characters in Unicode General Categories L*, M*, and N*.
The L (Letter) category consists of 5 subcategories: Ll,Lm,Lt,Lu,Lo. So I assume L* means all of L's subcategories.
I'll choose to look at the Ll subcategory (https://www.compart.com/en/unicode/category/Ll#UNC_SCRIPTS), and pick the character "æ" (U+00E6).
I can then see that the alphanumerics character set indeed contains this character. But when I add percent encoding to a string containing this character, it gets percent encoded.
"\u{E6}" // "æ"
CharacterSet.alphanumerics.contains("\u{E6}") // true
"æ".addingPercentEncoding(withAllowedCharacters: .alphanumerics) // "%C3%A6" 🤨
// Let's try with "a"
"\u{61}" // "a"
CharacterSet.alphanumerics.contains("\u{61}") // true
"a".addingPercentEncoding(withAllowedCharacters: .alphanumerics) // "a"
Why does this happen? It's in the allowed character set that I passed in, so it shouldn't be replaced, right?
I feel like it has something to do with the fact that "a" (U+0061) is also 0x61 in UTF-8 but "æ" (U+00E6) is [0xC3, 0xA6]; not 0xE6. Or that it takes up more than 1 byte?
String(data: Data([0x61]), encoding: .utf8)! // "a"
String(data: Data([0xC3, 0xA6]), encoding: .utf8)! // "æ"
String(data: Data([0xE6]), encoding: .utf8)! // crashes 🌋
Update
Is it because the percent encoding algorithm converts the string to Data and goes through 1 byte at a time? so it'll look at 0xC3 which isn't an allowed character, so that gets percent encoded. Then it'll look at 0xA6 which also isn't an allowed character, so that gets percent encoded too. So allowed characters technically have to be a single byte?
A truly allowed character has to be in the allowed character set, and be an ASCII character. Thanks #alobaili for pointing that out.
If you're curious, the predefined set CharacterSet.alphanumerics contains 129172 characters in total, but only 62 are truly allowed when this set is passed to a string's addingPercentEncoding(allowedSet:) method.
A quick way to inspect all the truly allowed characters in a particular CharacterSet can be done like so:
func inspect(charSet: CharacterSet) {
var characters: [String] = []
for char: UInt8 in 0..<128 { // ASCII range
let u = UnicodeScalar(char)
if charSet.contains(u) {
characters.append(String(u))
}
}
print("Characters:", characters.count)
print(characters)
}
inspect(charSet: .alphanumerics) // [a-z, A-Z, 0-9]
This is handy as you can't simply iterate through a CharacterSet. It can be useful to know what those allowed elements are. For example, the predefined CharacterSet.urlQueryAllowed only says:
Returns the character set for characters allowed in a query URL
component.
We can know what those allowed characters are:
inspect(charSet: .urlQueryAllowed)
// Characters: 81
// ["!", "$", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "=", "?", "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "_", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "~"]
Just For Fun
There's another (long, sure-fire) way, which looks at all the characters in the set (not just the ASCII ones), and compares a string of the character itself, with the string after adding percent encoding with only that character in the allowed set. When those two are equal then you know it really is an allowed character. Code adapted from this helpful article.
func inspect(charSet: CharacterSet) {
var characters: [String] = []
var allowed: [String] = []
var asciiCount = 0
for plane: UInt8 in 0..<17 {
if charSet.hasMember(inPlane: plane) {
let planeStart = UInt32(plane) << 16
let nextPlaneStart = (UInt32(plane) + 1) << 16
for char: UTF32Char in planeStart..<nextPlaneStart {
if let u = UnicodeScalar(char), charSet.contains(u) {
let s = String(u)
characters.append(s)
if s.addingPercentEncoding(withAllowedCharacters: CharacterSet([u])) == s {
allowed.append(s)
}
if u.isASCII {
asciiCount += 1
}
}
}
}
}
print("Characters:", characters.count)
print("Allowed:", allowed.count)
print("ASCII:", asciiCount)
}
inspect(charSet: .alphanumerics)
// Characters: 129172
// Allowed: 62
// ASCII: 62
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a string let string = "!101eggs". Now, I want to have an array like this ["!", "101", "e", "g", "g", "s"]. How can I do this?
I presume the hard part for you is "Where's the number"? As long as this is just a simple sequence of digits, a regular expression makes it easy to find:
let string = "!101eggs"
let patt = "\\d+"
let reg = try! NSRegularExpression(pattern:patt)
let r = reg.rangeOfFirstMatch(in: string,
options: [],
range: NSMakeRange(0,string.utf16.count)) // {1,3}
So now you know that the number starts at position 1 and is 3 characters long. The rest is left as an exercise for the reader.
Sorry It's too long
when input is
print("-1-2a000+4-1/000!00005gf101eg14g1s46nj3j4b1j5j23jj212j4b2j41234j01010101g0000z00005g0000".toArrayByNumber())
Result: ["-", "1", "-", "2", "a", "000", "+", "4", "-", "1", "/", "000", "!", "00005", "g", "f", "101", "e", "g", "14", "g", "1", "s", "46", "n", "j", "3", "j", "4", "b", "1", "j", "5", "j", "23", "j", "j", "212", "j", "4", "b", "2", "j", "41234", "j", "01010101", "g", "0000", "z", "00005", "g", "0000"]
extension Int {
func toZeroString() -> String {
return (0 ..< self).reduce("", { (result, zero) -> String in
return result + "0"
})
}
}
extension String {
func toArrayByNumber() -> [String] {
var array: [String] = []
var num = 0
var zeroCount = 0
var zeroEnd = false
for char in self.characters {
if let number = Int("\(char)") {
if zeroEnd == false && number == 0 {
zeroCount += 1
} else {
num = num * 10 + number
zeroEnd = true
}
} else {
if num != 0 {
array.append(zeroCount.toZeroString() + ("\(num)"))
} else if zeroCount > 0 {
array.append(zeroCount.toZeroString())
}
array.append(String(char))
num = 0
zeroCount = 0
zeroEnd = false
}
}
if num != 0 {
array.append(zeroCount.toZeroString() + ("\(num)"))
} else if zeroCount > 0 {
array.append(zeroCount.toZeroString())
}
return array
}
}
I've been trying to find this but I can't. I have the code:
func ayylmao(vorno: String){
if (vorno.(WHATEVER THE FUNCTION FOR FINDING A STRING GOES HERE)("a", "e", "i", "o", "u"))
{
print("Input Includes vowels")
}
}
but right at the if statement I can't find anything to check if the characters are in the string.
Like this:
let s = "hello"
let ok = s.characters.contains {"aeiou".characters.contains($0)} // true
I suggest two implementations:
func numberOfVowelsIn(_ string: String) -> Int {
let vowels: [Character] = ["a", "e", "i", "o", "u", "y", "A", "E", "I", "O", "U", "Y"]
return string.reduce(0, { $0 + (vowels.contains($1) ? 1 : 0) })
}
numberOfVowelsIn("hello my friend") //returns 5.
... and the second one with this code snippet hereafter to reach your goal:
let isVowel: (Character) -> Bool = { "aeiouyAEIOUY".contains($0) }
isVowel("B") //returns 'false'.
isVowel("a") //returns 'true'.
isVowel("U") //returns 'true'.