Use if-condition in string template - string

My Problem is to integrate an if-statement into a string template.
TYPES: BEGIN OF ty_field,
name TYPE string,
label TYPE string,
result TYPE string,
END OF ty_field.
DATA: mt_fields TYPE TABLE OF ty_field.
mt_fields = VALUE #(
( name = 'HI' label = 'Greeting' )
( name = 'PERSON' label = 'Who' )
( name = 'RESULT' label = 'Sentence' result = |Say \{HI\} to \{PERSON\}.| ) ).
Unfortunately the line 3 of mt_fields has result set to Say {HI} to {PERSON} but I'd expect Say Greeting to Who.
More importantly, what I want to get:
Some times there is no data for PERSON. In that case, the result variable will get the string 'Say hello to .' (if 'hello' is the value for HI).
I dont want to have this. If there is no person, I want to get an empty string as result. So I have to filter first, whether there is some value for PERSON or not. I need to get an if-condition into the string assignment.
In Python I would write something like
( name = 'RESULT' label = 'Sentence' result = 'Say {HI} to {PERSON}.' IF PERSON != '' ELSE '' )
But how to do this in ABAP?
Thanks a lot!

If I understood correctly what you are trying to do:
TYPES: BEGIN OF ty_field,
name TYPE string,
label TYPE string,
result TYPE string,
END OF ty_field.
DATA: mt_fields TYPE TABLE OF ty_field.
mt_fields = VALUE #( let salutation = 'Greeting' pers = cond string( when salutation = 'Hello' then '' else 'Who' ) IN
( name = 'HI' label = salutation )
( name = 'PERSON' label = pers )
( name = 'RESULT' label = 'Sentence' result = |Say { salutation } to { pers }.| ) ).

Related

Typescript custom compile time validation types

Is there any way that we can define types that are checked during typescript compile time only. I want user to define a value to variable (ie not going to change on runtime) and i want to check if that value matches some criteria. For example, user need to set numeric value but cannot set less then 5, or set an string with specific format or validate with regex eg email. or string that must follow specific format or it can be pass through some condition and pass the test or else throw the error with defined message
Is there any way to achieve this in typescript??
Numeric value
You are allowed to create a union of allowed numeric values. But then you have to set maximum allowed value and compute range. See this answer and my article.
Here you have small example:
type MAXIMUM_ALLOWED_BOUNDARY = 999
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? [...Result, Result['length']][number]
: ComputeRange<N, [...Result, Result['length']]>
)
type NumberRange = ComputeRange<MAXIMUM_ALLOWED_BOUNDARY>
type Except<N extends number, CustomRange extends number> = Exclude<CustomRange, N>
type GreaterThanFive = Except<ComputeRange<5>, NumberRange>
const less: GreaterThanFive = 2 //expected error
const greater: GreaterThanFive = 6 // ok
Playground
String with specific format.
You can use template literal strings
type SpecificFormat = `${string}-${string}`
type StringDigit = `${number}`
const str: SpecificFormat = 'hello-world' // ok
const str2: SpecificFormat = 'hello world' // expected error
const strDigit: StringDigit = '42' // ok
const strDigit2: StringDigit = '42a' // expected error
However, if you want to apply more advanced restrictions, for instance check whether it is a valid HEX value or email you need to use duplicate variable value in a type or use extra dummy function. See example:
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? Result[number]
: ComputeRange<N, [...Result, Result['length']]>
)
type HexNumber = `${ComputeRange<10>}`
type HexString =
| 'A'
| 'B'
| 'C'
| 'D'
| 'E'
| 'F'
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
type Hex = `${HexNumber}` | HexString;
type StringLength<
Str extends string,
Acc extends string[] = []
> =
(Str extends `${infer S}${infer Rest}`
? StringLength<Rest, [...Acc, S]>
: Acc['length'])
type ValidateLength<
Str extends string,
Length extends number
> =
(StringLength<Str> extends Length
? Str
: never)
type WithHash<T extends string> = `#${T}`
type ValidateHex<
Color extends string,
Cache extends string = '',
> =
Color extends `${infer A}${infer Rest}`
? (A extends ''
? WithHash<Cache>
: (A extends Hex
? ValidateHex<Rest, `${Cache}${A}`>
: never)
) : WithHash<Cache>
const hex: ValidateHex<'ffffff'> = '#ffffff' // ok
const hex2: ValidateHex<'fffffz'> = '#ffffff' // expected error
Playground
If you want to validate function arguments you can check this answer, this answer or my article
If you are interested in email validation you can check this answer or my article
Also it is possible to apply restriction where all chars should be lowercased or uppercased, fir this purpose you can use built in intrinsic utility types:
// credits goes to #jcalz https://stackoverflow.com/questions/68963491/define-a-typescript-type-that-takes-a-lowercase-word#answer-73732194
let str: Lowercase<string>;
str = "abc"; // okay
str = "DEF"; // error in TS4.8+
However, it works only for TS 4.8 +. See my article or this answer

What is a alternative for python classes in lua?

So i'm trying to convert python to lua but a road block i have right now is the class i'm not sure how i would convert a class to lua does anyone know how i would go about converting a class from python to lua?
python class
class
The OOP magic can be done with Lua tables and metatables.
Python
Look at The __init__() Function example here...
https://www.w3schools.com/python/python_classes.asp
Lets implement this with Lua...
( Lua 5.4 interactive console )
> _VERSION
Lua 5.4
> Person = setmetatable({},{
__call = function(self, name, age)
self.name = name
self.age = age
return {name = self.name, age = self.age}
end
})
> p1 = Person("John", 36)
> print(p1.name, p1.age)
John 36
So, some readers would ask: Why a metatabled table?
A simple function could do the same job.
Once a table has a metatable it is quit simple to add methods...
> Person = setmetatable({},{
__call = function(self, name, age)
self.name, self.age = name, age
table.insert(self, {name = self.name, age = self.age}) -- Numbered keys are the Data part
return {name = self.name, age = self.age}
end,
__index = {list = function(self) for i = 1, #self do print(self[i].name, self[i].age) end end}
})
> Person("John", 31);
> Person("Jack", 32);
> Person("Jim", 33);
> Person:list()
John 31
Jack 32
Jim 33
...that can handle the data of the table by itself.
Its a great benefit that the behaviour of a table can be controlled with metatables/methods.
And above example is only the tip of the iceberg.
Have a look at the __index of a string...
> for key, value in pairs(getmetatable(_VERSION).__index) do print(key, "=", value) end
byte = function: 0x565d6f20
lower = function: 0x565d4d90
len = function: 0x565d4750
sub = function: 0x565d7210
dump = function: 0x565d5d00
gsub = function: 0x565d7dc0
char = function: 0x565d5060
unpack = function: 0x565d6530
match = function: 0x565d7da0
packsize = function: 0x565d6420
pack = function: 0x565d6950
upper = function: 0x565d4ac0
format = function: 0x565d52d0
reverse = function: 0x565d4b50
find = function: 0x565d7db0
gmatch = function: 0x565d70d0
rep = function: 0x565d4be0
Therefore this is possible...
> print(("koyaanisqatsi"):upper():reverse())
ISTAQSINAAYOK
Means: Methods can be chained if their returning datatype has a method
Exceptions are: len() accept but dont return a string and sub() needs numbers before it returns a string also dump() needs a self defined function and returns a binary (almost unreadable) string.

Swift, use string name to reference a variable

Plan to use a string value to for referencing which variable I want to update. Combining string from a few different user selected sources. To many possibilities to use if/case statements. Thanks in advance
var d1000: Int = 0
// ...
var d1289: Int = 0
// ...
var d1999: Int = 0
var deviceIDtype: Character = "d" // button press assigns some value, d used for example
var deviceIDsection: String = "12" // button press assigns some value, 12 used for example
var deviceID: String = "89" // button press assigns some value, 89 used for example
var ref:String = ""
func devName(dIDt:Character, dIDs: String, dID: String) -> String {
var combine: String = String(dIDt) + (dIDs) + (dID)
return (combine)
}
ref = devName(deviceIDtype, dIDs: deviceIDsection, dID: deviceID) // ref equals d1289 in this example
// d1289 = 1234 // trying to set this using the ref variable value, failed attempts below
/(ref) = 1234 // set d1289 variable to equal "1234"
"/(ref)" = 1234 // set d1289 variable to equal "1234"
get(ref) = 1234 // set d1289 variable to equal "1234"
get.ref = 1234 // set d1289 variable to equal "1234"
It is possible!!!
let index = 1000
if let d1000 = self.value(forKey: "d\(index)") as? Int {
// enjoy
}
How about using a dictionary, [String : Int]?
This will allow you to achieve what you want - storing values for different keys.
For example, instead of using
var d1000 = 0
var d1289 = 0
var d1999 = 0
You could use
var dictionary: [String : Int] = [
"d1000" : 0,
"d1289" : 0,
"d1999" : 0
]
To store a value in the dictionary, just use
dictionary[key] = value
//for example, setting "d1289" to 1234
dictionary["d1289"] = 1234
and to get the value from the dictionary, use
let value = dictionary[key]
//for example, getting the value of "d1289"
let value = dictionary["d1289"]
So, you could use something like this
//initialize your dictionary
var myDictionary: [String : Int] = [:]
//your key initialization data
var deviceIDtype: Character = "d"
var deviceIDsection: String = "12"
var deviceID: String = "89"
var ref: String = ""
//your code
func devName(/*...*/){/*...*/}
ref = devName(/*...*/)
//set the key ref (fetched from devName) to 1234
myDictionary[ref] = 1234
Just as a side note, you could really clean some of your code
func devName(type: Character, section: String, id: String) -> String{
return String(type) + section + id
}
//...
let key = devName(deviceIDtype, section: deviceIDsection, id: deviceID)
let value = 1234
myDictionary[key] = value

Swift OS X String to Int Conversion Error

I'm having trouble converting a String to Int in my Swift OS X Xcode project. I have some data saved in a text file in a comma delimited format. The contents of the text file is below:
1,Cessna 172,3,54.4,124,38.6112
(and a line break at the end)
I read the text file and seperate it, first by \n to get each line by itself, and then by , to get each element by itself. The code to do this is below:
if let dir : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first {
let path = dir.stringByAppendingPathComponent("FSPassengers/aircraft.txt")
do {
let content = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
if content != "" {
let astrContent:[String] = content.componentsSeparatedByString("\n")
for aeroplane in astrContent {
let aSeperated:[String] = aeroplane.componentsSeparatedByString(",")
print(aSeperated[0])
print(Int(aSeperated[0]))
//self.aAircraft.append(Aircraft(id: aSeperated[0], type: aSeperated[1], passengerCapacity: Int(aSeperated[2])!, cargoCapacityKg: Double(aSeperated[3])!, cruiseSpeed: Int(aSeperated[4])!, fuelLitresPerHour: Double(aSeperated[5])!))
}
}
}
catch {
print("Error")
}
}
The end result here will be to assign each record (each line of the text file) into the array aAircraft. This array is made up of a custom object called Aircraft. The custom class is below:
class Aircraft: NSObject {
var id:Int = Int()
var type:String = String()
var passengerCapacity:Int = Int()
var cargoCapacityKg:Double = Double()
var cruiseSpeed:Int = Int()
var fuelLitresPerHour:Double = Double()
override init() {}
init(id:Int, type:String, passengerCapacity:Int, cargoCapacityKg:Double, cruiseSpeed:Int, fuelLitresPerHour:Double) {
self.id = id
self.type = type
self.passengerCapacity = passengerCapacity
self.cargoCapacityKg = cargoCapacityKg
self.cruiseSpeed = cruiseSpeed
self.fuelLitresPerHour = fuelLitresPerHour
}
}
In the first code extract above, where I split the text file contents and attempt to assign them into the array, you will see that I have commented out the append line. I have done this to get the application to compile, at the moment it is throwing me errors.
The error revolves around the conversion of the String values to Int and Double values as required. For example, Aircraft.id, or aSeperated[0] needs to be an Int. You can see that I use the line Int(aSeperated[0]) to convert the String to Int in order to assign it into the custom object. However, this line of code is failing.
The two print statements in the first code extract output the following values:
1
Optional(1)
If I add a ! to the end of the second print statement to make them:
print(aSeperated[0])
print(Int(aSeperated[0])!)
I get the following output:
I understand what the error means, that it tried to unwrap an optional value because I force unwrapped it, and it couldn't find an Int value within the string I passed to it, but I don't understand why I am getting the error. The string value is 1, which is very clearly an integer. What am I doing wrong?
Because Casena 172 is not convertible to an Int. You also have other decimal numbers which you will lose precision when casting them to Int. Use NSScanner to create an initializer from a CSV string:
init(csvString: String) {
let scanner = NSScanner(string: csvString)
var type: NSString?
scanner.scanInteger(&self.id)
scanner.scanLocation += 1
scanner.scanUpToString(",", intoString: &type)
self.type = type as! String
scanner.scanLocation += 1
scanner.scanInteger(&self.passengerCapacity)
scanner.scanLocation += 1
scanner.scanDouble(&self.cargoCapacityKg)
scanner.scanLocation += 1
scanner.scanInteger(&self.cruiseSpeed)
scanner.scanLocation += 1
scanner.scanDouble(&self.fuelLitresPerHour)
}
Usage:
let aircraft = Aircraft(csvString: "1,Cessna 172,3,54.4,124,38.6112")
As #mrkxbt mentioned, the issue was related to the blank line after the data in the text file. The string was being split at the \n which was assigning two values into the array. The first value was a string containing the data and the second was an empty string, so obviously the second set of splitting (by ,) was failing. Amended and working code is below:
if let dir : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first {
let path = dir.stringByAppendingPathComponent("FSPassengers/aircraft.txt")
do {
let content = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
if content != "" {
let astrContent:[String] = content.componentsSeparatedByString("\n")
for aeroplane in astrContent {
if aeroplane != "" {
let aSeperated:[String] = aeroplane.componentsSeparatedByString(",")
print(aSeperated[0])
print(Int(aSeperated[0])!)
self.aAircraft.append(Aircraft(id: Int(aSeperated[0])!, type: aSeperated[1], passengerCapacity: Int(aSeperated[2])!, cargoCapacityKg: Double(aSeperated[3])!, cruiseSpeed: Int(aSeperated[4])!, fuelLitresPerHour: Double(aSeperated[5])!))
}
}
}
}
catch {
print("Error")
}
}

match check in matlab

i have strings like these:
s{1,2} = 'string';
s{2,2} = 'string2';
and in workspace structure like this
U.W.string = [2 2.5 3]
I want to check (in loop) s{1,2} or s{2,2} or s{i,2} matches any structure with the same name. If so, assign values from this structure to some variable var(i). How can it be done?
Use isfields to check, if a string is the name of a field in a struct. Then use the syntax struct.(name), where name is a string to access the field. Your code might look something like:
test = struct('hello', 'world', 'count', 42, 'mean', 10);
fields = {'test', 'count';
'hello', 'text';
'more', 'less'};
values = {pi, 'dummy', -1};
for row = 1 : size(fields, 1)
for column = 1 : size(fields, 2)
if isfield(test, fields{row, column})
test.(fields{row, column}) = values{row};
end
end
end
This converts the initial struct
test =
hello: 'world'
count: 42
mean: 10
to this one
test =
hello: 'dummy'
count: 3.1416
mean: 10
A shorter implementation is achieved by removing the inner loop and giving a cell-array to isfields:
for row = 1 : size(fields, 1)
%# Note the parenthesis instead of curly braces in the next statement.
match = isfield(test, fields(row, :));
if any(match)
test.(fields{row, match}) = values{row};
end
end
Use isfield(structName,fieldName). This should do the trick:
strings{1,1} = 'foo';
strings{1,2} = 'bar';
strings{1, 3} = 'foobar';
U.W.foo = 1;
U.W.foobar = 5;
for idx = 1:length(strings)
if(isfield(U.W,strings{1,idx}))
expression = sprintf('outvar(idx) = U.W.%s',strings{1,idx});
eval(expression);
end
end

Resources