I have a table in the form of driver start number and driver name. Now I want to determine the driver name based on the start number. Which solution approach can I follow for this?
20 - driver name A
44 - driver name B
4 - driver name C
......
That would be my approach:
String ReturnDriver(int startNumber) {
Switch(startNumber) {
case 20:
{
return "driver name A";
}
break;
case 44:
{
return "driver name B";
}
break;
case 4:
{
return "driver name C";
}
break;
}
}
Would be nice if Arduino had something similar to key/value pair dictionaries. I'm not sure what your data looks like, but I wrote a little function that can emulate key/value pairs using a string of names and numbers:
String getName(int n){
int start = input.indexOf(":",input.indexOf(String(n)));
int end = input.indexOf(",", start++);
if(end < 0) end = input.length();
String value = input.substring(start, end);
value.trim();
return value;
}
You can change the separating character to be whatever you need.
You can write some code to combine the data you have into a string like so:
String input = "20: Driver,"
"4: Name,"
"23: David";
or
String input = "20: Driver, 4: Name, 23: David";
find a name in a string:
Serial.print(getName(4));
> Name
Or if your drivers occupy all positions, just order them in an array:
//each element has an id starting from 0
String name[] = {"Name", "Driver", "David"};
position = 1; //array element 2
Serial.print(name[position]);
Related
My program reads a line from a file. This line contains comma-separated text like:
123,test,444,"don't split, this",more test,1
I would like the result of a split to be this:
123
test
444
"don't split, this"
more test
1
If I use the String.split(","), I would get this:
123
test
444
"don't split
this"
more test
1
In other words: The comma in the substring "don't split, this" is not a separator. How to deal with this?
You can try out this regex:
str.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
This splits the string on , that is followed by an even number of double quotes. In other words, it splits on comma outside the double quotes. This will work provided you have balanced quotes in your string.
Explanation:
, // Split on comma
(?= // Followed by
(?: // Start a non-capture group
[^"]* // 0 or more non-quote characters
" // 1 quote
[^"]* // 0 or more non-quote characters
" // 1 quote
)* // 0 or more repetition of non-capture group (multiple of 2 quotes will be even)
[^"]* // Finally 0 or more non-quotes
$ // Till the end (This is necessary, else every comma will satisfy the condition)
)
You can even type like this in your code, using (?x) modifier with your regex. The modifier ignores any whitespaces in your regex, so it's becomes more easy to read a regex broken into multiple lines like so:
String[] arr = str.split("(?x) " +
", " + // Split on comma
"(?= " + // Followed by
" (?: " + // Start a non-capture group
" [^\"]* " + // 0 or more non-quote characters
" \" " + // 1 quote
" [^\"]* " + // 0 or more non-quote characters
" \" " + // 1 quote
" )* " + // 0 or more repetition of non-capture group (multiple of 2 quotes will be even)
" [^\"]* " + // Finally 0 or more non-quotes
" $ " + // Till the end (This is necessary, else every comma will satisfy the condition)
") " // End look-ahead
);
Why Split when you can Match?
Resurrecting this question because for some reason, the easy solution wasn't mentioned. Here is our beautifully compact regex:
"[^"]*"|[^,]+
This will match all the desired fragments (see demo).
Explanation
With "[^"]*", we match complete "double-quoted strings"
or |
we match [^,]+ any characters that are not a comma.
A possible refinement is to improve the string side of the alternation to allow the quoted strings to include escaped quotes.
Building upon #zx81's answer, cause matching idea is really nice, I've added Java 9 results call, which returns a Stream. Since OP wanted to use split, I've collected to String[], as split does.
Caution if you have spaces after your comma-separators (a, b, "c,d"). Then you need to change the pattern.
Jshell demo
$ jshell
-> String so = "123,test,444,\"don't split, this\",more test,1";
| Added variable so of type String with initial value "123,test,444,"don't split, this",more test,1"
-> Pattern.compile("\"[^\"]*\"|[^,]+").matcher(so).results();
| Expression value is: java.util.stream.ReferencePipeline$Head#2038ae61
| assigned to temporary variable $68 of type java.util.stream.Stream<MatchResult>
-> $68.map(MatchResult::group).toArray(String[]::new);
| Expression value is: [Ljava.lang.String;#6b09bb57
| assigned to temporary variable $69 of type String[]
-> Arrays.stream($69).forEach(System.out::println);
123
test
444
"don't split, this"
more test
1
Code
String so = "123,test,444,\"don't split, this\",more test,1";
Pattern.compile("\"[^\"]*\"|[^,]+")
.matcher(so)
.results()
.map(MatchResult::group)
.toArray(String[]::new);
Explanation
Regex [^"] matches: a quote, anything but a quote, a quote.
Regex [^"]* matches: a quote, anything but a quote 0 (or more) times , a quote.
That regex needs to go first to "win", otherwise matching anything but a comma 1 or more times - that is: [^,]+ - would "win".
results() requires Java 9 or higher.
It returns Stream<MatchResult>, which I map using group() call and collect to array of Strings. Parameterless toArray() call would return Object[].
You can do this very easily without complex regular expression:
Split on the character ". You get a list of Strings
Process each string in the list: Split every string that is on an even position in the List (starting indexing with zero) on "," (you get a list inside a list), leave every odd positioned string alone (directly putting it in a list inside the list).
Join the list of lists, so you get only a list.
If you want to handle quoting of '"', you have to adapt the algorithm a little bit (joining some parts, you have incorrectly split of, or changing splitting to simple regexp), but the basic structure stays.
So basically it is something like this:
public class SplitTest {
public static void main(String[] args) {
final String splitMe="123,test,444,\"don't split, this\",more test,1";
final String[] splitByQuote=splitMe.split("\"");
final String[][] splitByComma=new String[splitByQuote.length][];
for(int i=0;i<splitByQuote.length;i++) {
String part=splitByQuote[i];
if (i % 2 == 0){
splitByComma[i]=part.split(",");
}else{
splitByComma[i]=new String[1];
splitByComma[i][0]=part;
}
}
for (String parts[] : splitByComma) {
for (String part : parts) {
System.out.println(part);
}
}
}
}
This will be much cleaner with lambdas, promised!
Please see the below code snippet. This code only considers happy flow. Change the according to your requirement
public static String[] splitWithEscape(final String str, char split,
char escapeCharacter) {
final List<String> list = new LinkedList<String>();
char[] cArr = str.toCharArray();
boolean isEscape = false;
StringBuilder sb = new StringBuilder();
for (char c : cArr) {
if (isEscape && c != escapeCharacter) {
sb.append(c);
} else if (c != split && c != escapeCharacter) {
sb.append(c);
} else if (c == escapeCharacter) {
if (!isEscape) {
isEscape = true;
if (sb.length() > 0) {
list.add(sb.toString());
sb = new StringBuilder();
}
} else {
isEscape = false;
}
} else if (c == split) {
list.add(sb.toString());
sb = new StringBuilder();
}
}
if (sb.length() > 0) {
list.add(sb.toString());
}
String[] strArr = new String[list.size()];
return list.toArray(strArr);
}
My table column ("ID") in which the celldata has some string and integers represented below.
ID
abc1
fgd5
hgt9
ftg7
I should get the following result after sort:
ID
abc1
fgd5
ftg7
hgt9
So how can I sort this column based on only the integer values in the column data.
Assuming
TableColumn<SomeEntity, String> idColumn ;
You can do
// any number of non-digits (consumed greedily),
// followed by any number of digits (consumed greedily, as a group named "value"),
// followed by anything
Pattern pattern = Pattern.compile("\\D*(?<value>\\d*).*");
idColumn.setComparator(Comparator.comparingInt(id -> {
Matcher matcher = pattern.matcher(id);
// value to return if no match:
int defaultValue = 0 ;
if (matcher.matches()) {
// get the portion of the match that matched the group named "value":
String value = matcher.group("value");
if (value.isEmpty()) {
return defaultValue ;
} else {
// convert to an int:
return Integer.parseInt(value);
}
} else {
return defaultValue ;
}
}));
I'm trying to improve the AutoFilterRow functionality for one of my columns. The column will always consist of a string that represents a range of values like this: "num1 - num2". I would like to allow end users to type a value into the cell in the AutoFilterRow and in this particular column and the rows whose sections have a range that includes the number they typed. For instance, if I had 3 rows and each of their section attributes were the following: "1 - 4", "1 - 6", and "4 - 6", and a user types "3" into the AutoFilterRow cell for this column, I would expect the rows containing "1 - 4" and "1 - 6".
I have already overwritten the CreateAutoFilterCriterion in MyGridView to allow for additional operators as suggested in several examples found on this site:
protected override CriteriaOperator CreateAutoFilterCriterion(GridColumn column, AutoFilterCondition condition, object _value, string strVal)
{
if ((column.ColumnType == typeof(double) || column.ColumnType == typeof(float) || column.ColumnType == typeof(int)) && strVal.Length > 0)
{
BinaryOperatorType type = BinaryOperatorType.Equal;
string operand = string.Empty;
if (strVal.Length > 1)
{
operand = strVal.Substring(0, 2);
if (operand.Equals(">="))
type = BinaryOperatorType.GreaterOrEqual;
else if (operand.Equals("<="))
type = BinaryOperatorType.LessOrEqual;
else if (operand.Equals("<>"))
type = BinaryOperatorType.NotEqual;
}
if (type == BinaryOperatorType.Equal)
{
operand = strVal.Substring(0, 1);
if (operand.Equals(">"))
type = BinaryOperatorType.Greater;
else if (operand.Equals("<"))
type = BinaryOperatorType.Less;
else if (operand.Equals("!") || operand.Equals("~"))
type = BinaryOperatorType.NotEqual;
}
if (type != BinaryOperatorType.Equal)
{
string val = strVal.Replace(operand, string.Empty);
try
{
if (!val.IsEmpty())
{
if (column.ColumnType == typeof(double))
{
var num = Double.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
return new BinaryOperator(column.FieldName, num, type);
}
if (column.ColumnType == typeof(float))
{
var num = float.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
return new BinaryOperator(column.FieldName, num, type);
}
else
{
var num = int.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
return new BinaryOperator(column.FieldName, num, type);
}
}
// DateTime example:
// DateTime dt = DateTime.ParseExact(val, "d", column.RealColumnEdit.EditFormat.Format);
// return new BinaryOperator(column.FieldName, dt, type);
}
catch
{
return null;
}
}
}
//
// HERE IS WHERE I WANT TO ADD THE FUNCTIONALITY I'M SPEAKING OF
//
else if (column.FieldName == "SectionDisplayUnits")
{
try
{
if (!strVal.IsEmpty())
{
}
}
catch
{
return null;
}
}
return base.CreateAutoFilterCriterion(column, condition, _value, strVal);
}
How would I go about doing that? I figure I want to split each string with a call to Split(...) like this: cellString.Split(' - '). Then I would parse each string returned from the call to Split(...) into a number so that I could use inequality operators. But I'm just not sure how to go about doing this. Can I get some help? Thanks!
Update:
Please take a look here for a more in-depth discussion on this matter with myself and a knowledgeable DevExpress representative. I received a lot of help and I wanted to share this knowledge with whoever needs similar assistance. Here is the link.
Using C#, you would split the value into two parts, convert them to the number, and compare the value entered by the user with both values to ensure that it is greater or equal the first part and less or equal the second part.
In Criteria Language, the same functionality can be created using Function Operators. However, the expression will be a bit complex. Please try the following. It will work only if the format of values in the SectionDisplayUnits column is fixed, and the value always consists of two numbers delimited by "-".
string rangeDelimiter = "-";
return CriteriaOperator.Parse("toint(trim(substring(SectionDisplayUnits, 0, charindex(?, SectionDisplayUnits)))) <= ? && toint(trim(substring(SectionDisplayUnits, charindex(?, SectionDisplayUnits) + 1, len(SectionDisplayUnits) - charIndex(?, SectionDisplayUnits) - 1))) >= ?", rangeDelimiter, _value, rangeDelimiter, rangeDelimiter, _value);
on the web service side I am applying
StoreRequestParameters parameters = new StoreRequestParameters(this.Context);
string condition= parameters.GridFilters.ToString();
//I ma sending this to the methot "List<Ks> Get(....)"
to get the gridfilter parameters.
inside the other methot ,trying to get the selected gridfilters values like this.
public List<Ks> Get(int start, int limit, string sort, string terssiralama, string condition, out int totalrow)
{
FilterConditions fc = new FilterConditions(condition);
foreach (FilterCondition cnd in fc.Conditions)
{
Comparison comparison = cnd.Comparison;
string fi = cnd.Field;
FilterType type = cnd.Type;
switch (cnd.Type)
{
case FilterType.Date:
switch (comparison)
{
case Comparison.Eq:
field1 = cnd.Field;
cmp1 = "=";
value1 = cnd.Value<string>();
...........
..........
}
but I failed getting the values like this
FilterConditions fc = new FilterConditions(condition);
I couldnt pass the string values .
should I serializes or deserilized first ?
StoreRequestParameters parameters = new StoreRequestParameters(this.Context);
instead of using this, string condition= parameters.GridFilters.ToString();
I use this
string obj = this.Context.Request["filter"];
and pass it to the
FilterConditions fc = new FilterConditions(obj);
It can be reach all filter condition in fc filtercondition variable.
According to MSDN on DateTime.ToString ToString("s") should always return string in the format of the sortable XML Schema style formatting, e.g.: 2008-10-01T17:04:32.0000000
In Reflector I came to this pattern inside DateTimeFormatInfo.
public string SortableDateTimePattern
{
get
{
return "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
}
}
Does DateTime.ToString("s") return always a string in this format?
Regardless the Culture, Region, ...
Yes it does
Code to test that
var dateTime = DateTime.Now;
var originialString = dateTime.ToString("s");
string testString;
foreach (var c in System.Globalization.CultureInfo.GetCultures(CultureTypes.AllCultures))
{
Thread.CurrentThread.CurrentUICulture = c;
if (c.IsNeutralCulture == false)
{
Thread.CurrentThread.CurrentCulture = c;
}
testString = dateTime.ToString("s");
Console.WriteLine("{0} ", testString);
if (originialString != testString)
{
throw new ApplicationException(string.Format("ToString(s) is returning something different for {0} " , c));
}
}
Yes it does. As others have said it only contains numeric values and string literals (e.g. 'T' and ':'), nothing that is altered by region or culture settings.
Yep. Breaking that pattern down, it's only numeric properties, there's no reference to anything like month or day names in there.
yyyy - 4 digit date
MM - 2 digit month, with leading zero
dd - 2 digit day, with leading zero
T - a literal T
HH - 2 digit hour, with leading zero, 24 hour format
mm - 2 digit minute, with leading zero
ss - 2 digit second, with leading zero