Goal of this expression is separate mathematic calculations into operators, symbols, numbers and brackets.
For example:
Input string: 1+3-6*(12-3+4/5)
Output list: 1, +, 3, -, 6, *, (12-3+4/5)
So I built this expression.
It is working on the web page, but in the Dart code this happens:
final calculationExpression = RegExp(
r"/(\(([a-zA-Z0-9-+/*]+)\))|([a-zA-Z0-9]+)|([+/*-]{1})/g",
unicode: true,
multiLine: true,
);
...
List<String> operators = calculationsString.split(calculationExpression); /// Output: ["", "+", "-", ...]
What did I do wrong?
The syntax /pattern/g is used to create regular expression literals in JavaScript (and sed and some other languages), just as quotes are used to create string literals. Dart doesn't have regular expression literals; you instead must invoke the RegExp constructor directly. Combining a regular expression literal syntax with an explicitly constructed RegExp object makes no sense. When you do RegExp(r'/pattern1|pattern2|pattern3/g'), you're actually matching against /pattern1 (pattern1 prefixed with a literal / character) or pattern2 or pattern3/g (pattern3 followed by a literal string /g).
String.split does not split the input string such that each element of the result matches the pattern. It treats all matches of the pattern as separators. Consequently, the resulting list will not have any elements that match the pattern, which is the opposite of what you want. You instead want to find all matches of the pattern in the string. You instead can use RegExp.allMatches if you additionally verify that the input string contains only matches from the regular expression.
Putting it all together:
void main() {
final calculationExpression = RegExp(
r"(\(([a-zA-Z0-9-+/*]+)\))|([a-zA-Z0-9]+)|([+/*-]{1})",
unicode: true,
multiLine: true,
);
var calculationsString = '1+3-6*(12-3+4/5)';
// Prints: [1, +, 3, -, 6, *, (12-3+4/5)]
print(calculationsString.tokenizeFrom(calculationExpression).toList());
}
extension on String {
Iterable<String> tokenizeFrom(RegExp regExp) sync* {
void failIf(bool condition) {
if (condition) {
throw FormatException(
'$this contains characters that do not match $regExp',
);
}
}
var matches = regExp.allMatches(this);
var lastEnd = 0;
for (var match in matches) {
// Verify that there aren't unmatched characters.
failIf(match.start != lastEnd);
lastEnd = match.end;
yield match.group(0)!;
}
failIf(lastEnd != length);
}
}
You put the JavaScript regexp literal slashes and flags inside the Dart string.
If you remove the leading / and trailing /g, you get the RegExp you intended to.
The multiLine and unicode flags are unnecessary (your regexp doesn't use any feature affected by those)
The Dart split function does not emit capture groups, so you probably want to look at getting the matches, not removing them, which is what split does.
All in all, try:
final calculationExpression = RegExp(
r"\([a-zA-Z\d\-+/*]+\)|[a-zA-Z\d]+|[+/*\-]");
List<String> tokes =
calculationExpression.allMatches(calculationsString).toList();
Related
I have a regex expression that I'm trying to create dynamically.
RegExp reg4 = RegExp(r'(two+\s\w+\s+one)');
My intention is to replace the value at two to be set dynamically
I've tried this
var two = "two";
RegExp reg4 = RegExp(r'(' + two + '+\s\w+\s+one)');
But it doesn't work.
You forgot the r on the second part of the string:
var two = "two";
RegExp reg4 = RegExp(r'(' + two + r'+\s\w+\s+one)');
// ^ <- that one!
Without that r, the \ss and \w in the second string are interpreted as string escapes, and disappear before they get to the RegExp parser.
I'll also point out that the result of (two+\s\w+\s+one) has a + applying to only the o of two.
You might want to create ((?:two)+\s\w+\s+one) instead, so you repeat the entire "two" string.
Another thing to consider is whether you want to match the two variable's string verbatim, or if it can contain a RegExp too.
If you want it verbatim, so that a value of var two = "[NOTE]"; won't match a single character, the string should be escaped:
RegExp reg4 = RegExp(r'((?:' + RegExp.escape(two) + r')+\s\w\s+one)');
i know i can construct tables like this:
local t= {
first = "value1",
second = "value2"
}
and i now i can use keys containing spaces like t["some key"] = "some value"
but is there a way to construct table like above with keys containing spaces?
I tried a few things, but i only goit errors
You can declare any expression as a key in a table constructor by putting it in brackets:
local t = {
["some key"] = "some value",
[234567 + 2] = "other value",
}
local t= {
first = "value1",
second = "value2"
}
Is syntactic sugar for
local t= {
["first"] = "value1",
["second"] = "value2"
}
This convenient syntax only works for names. Lua names may only consist of letters, numbers and underscore and they must not start with a number.
As a valid Lua identifer may not contain a space you cannot use the syntactic sugar. Hence the only way to do this is to use the full syntax
local t = {["hello world"] = 1}
This also applies to indexing that table field. So the only way is t["hello world"]
I'm studying Dart and I don't have enough practical examples to understand some of the topics.
So there is a task to turn a string into a list, so that numbers consisting of several characters become one element of the list. Example:
String a = '65bf+(100.46+22)/hf2-1' => List<String> arr ['65', 'b', 'f', '+', '(', '100.46', '+', '22', ')', '/', 'd', 'h', 'f', '2', '-', '1']
The length of the string can be any. Numbers in a string can be either integers or decimals.
It seems to me that here you can turn a string into a necessary list by generating a new list using a regular expression. However, attempts to do something working were not successful.
I will be grateful for any help.
This worked for me in dartpad:
import 'dart:convert'; // for json
void main() {
String a = '65bf+(100.46+22)/hf2-1';
var matcher = RegExp(r'([0-9.]+|.)');
var matches = matcher.allMatches(a).map((e) => e.group(0));
print(matches);
print(json.encode(matches.toList()));
}
Output is:
(65, b, f, +, (, 100.46, +, 22, ), /, h, f, 2, -, 1)
["65","b","f","+","(","100.46","+","22",")","/","h","f","2","-","1"]
The CONTAINS($val1, $val2, $delim) function in AppwayScript checks whether a delimiter separated string contains a certain value as a substring.
So, e.g.:
CONTAINS('a|b|c', 'b', '|') == true
but
CONTAINS('aa|bb|cc', 'b', '|') == false
How do I perform a simple string inclusion test in AppwayScript?
Instead, try:
MATCH('aa|bb|cc', 'b')
Say that you want to create a Lua table, and all its keys are valid lua identifiers. Then you can use the key=value syntax:
local niceTable = { I=1, like=1, this=1, syntax=1 }
If however your strings are not "identifiable", then you have to use the ['key']=value syntax:
local operators = { ['*']="Why", ['+']="the", ['/']="brackets", ['?']='?' }
I'm a bit baffled about this. What are those brackets doing there? What do they mean?
They identify the contained string as a key in the resulting table. The first form, you could consider as equal to
local niceTable = {}
niceTable.I = 1;
niceTable.like = 1;
The second form is equal to
local operators = {}
operators['*'] = "Why";
operators['+'] = "The";
The difference is purely syntactic sugar, except where the first one uses identifiers, so it has to follow the identifier rules, such as doesn't start with a number and interpret-time constant, and the second form uses any old string, so it can be determined at runtime, for example, and a string that's not a legal identifier. However, the result is fundamentally the same. The need for the brackets is easily explained.
local var = 5;
local table = {
var = 5;
};
-- table.var = 5;
Here, var is the identifier, not the variable.
local table = {
[var] = 5;
};
-- table[5] = 5;
Here, var is the variable, not the identifier.
The normal syntax for indexing a table is t[val]. For string keys only, Lua provides an alternate syntax, where t.foo is exactly equivalent to t["foo"]. This is purely a syntactical convenience, so-called 'syntax sugar'. It doesn't add functionality, it just gives you a less cluttered syntax for using strings as named fields.
There are a lot of strings keys this won't work for:
t["hello_world"] => t.hello_world -- works
t["hello world"] => t.hello world -- oops, space in the string
t["5 * 3"] => t.5 * 3 -- oops
t['[10]'] => t.[10] -- oops
Basically it only works if the string key would be a valid identifier.
Again, tables are indexed via [], and in most cases you need to use them:
t = {
-- [key] = value
[10] = "ten", -- number key, string value
["print function"] = print, -- string key, function value
["sub table"] = {}, -- string key, table value
[print] = 111, -- function key, number value
["foo"] = 123, -- string key, number value
}
Only if you're using a string key which would work as a valid identifier (no spaces, contains only word characters, numbers, or underlines, and doesn't begin with a number) can you use the shortcut syntax. For the table above, that would be only 'foo':
t = {
-- [key] = value
[10] = "ten", -- number key, string value
["print function"] = print, -- string key, function value
["sub table"] = {}, -- string key, table value
[print] = 111, -- function key, number value
foo = 123, -- string key, number value
}