I am sending some code to R.net wrapper as strings. If there are no any quation marks inside , it's simple with #
engine.Evaluate(#"remove_outliersabove <- function(x, na.rm = TRUE, ...) {
qnt <- quantile(x, probs=c(.25, .75), na.rm = na.rm, ...);
H <- 1.5 * IQR(x, na.rm = na.rm);
y <- x;
y[x > (qnt[2] + H)] <- NA;
y;
}");
but if I have "" inside then things get complicated and I need to cut and join strings like this
engine.Evaluate("for (k in 1:length(dates))" +
"{ " +
"tmp <- grep(dates[[k]],as.Date(data$timestamp, format=\"%d/%m/%Y\"))" +
"if (length(tmp)!=96)" +
"{ " +
"to_remove[[it]]=k it=it+1" +
"}" +
"}");
is there better option ? for example to use # and then mark quation mark somehow ?
When you use #"...", you can escape the " character by doubling it to "". So
string str = "hello ""world""!";
is
hello "world"!
How about string.Format("{0} bla bla {1}",string1,string2)? does it make it look neater?
Related
I have a list of names and I loop through them to create a comma separated list in a string variable (Bob, George, Will, Terry).
I need the list to eventually look like (Bob, George, Will and Terry).
How do I find the LAST instance of the comma and replace it with the word "and"? Once I find the LAST instance, I think it's a simple matter of doing something like
string new=ori.Substring(0,start) + rep + ori.Substring(start+rep.Length);
Thoughts? Comments? Suggestions?
Thanks,
Bob
This should work for you. Added the alternative comma style as well.
var names = "Bob, George, Will, Terry";
var lastCommaPosition = names.LastIndexOf(',');
if (lastCommaPosition != -1)
{
names = names.Remove(lastCommaPosition, 1)
//.Insert(lastComma, " and");
.Insert(lastCommaPosition, ", and");
}
Console.WriteLine(names);
You can use a combination of LINQ and String.Join. This solution does not need the last index of a comma and is "more fluent" to read.
var list = new List<string> { "Bob", "George", "Will", "Terry" };
var listAsString = list.Count > 1
? string.Join(", ", list.Take(list.Count - 1)) + " and " + list.Last()
: list.First();
You can use Linq,
list.Select(i => i).Aggregate((i, j) => i + (list.IndexOf(j) == list.Count -1 ? " and " : " , ") + j);
Hope helps,
This should do the trick for you:
var foo = "Bob, George, Will, Terry";
if (foo.Contains(",")) {
foo = foo.Substring(0, foo.LastIndexOf(",")) + " and" + foo.Substring(foo.LastIndexOf(",")+ 1);
}
I'm not sure what you wanted to do, but the following code works:
string original = "(Bob, George, Will, Terry)";
string result = "";
string[] splited = original.Split(',');
for (int i = 0; i < splited.Count(); i++)
{
if(i == splited.Count() - 2)
{
result += splited[i] + " and";
}
else if(i == splited.Count() - 1)
{
result += splited[i];
}
else
{
result += splited[i] + ",";
}
}
I Used split to split the original string in a vector so i worked with this vector to replace the last comma to the word "and".
I'm working on to read a textfile which contains this line of string. And to fetch its value to my integer variables.. I want to try to avoid using Class or Arrays.
string cont = "[]val1:1val2:0val3:1";
int split = cont.IndexOf("val3:");
int val3 = Int32.Parse(cont.Substring(split + 5)); // this line successfully convert string to int
cont.Remove(split);
Console.WriteLine("Value3: " + val3 + " Content: " + cont);
split = cont.IndexOf("val2:");
int val2 = Int32.Parse(cont.Substring(split + 5)); // LINE 21
cont.Remove(split);
Console.WriteLine("Value2: " + val2 + " Content: " + cont);
split = cont.IndexOf("val1:");
int SilverCoins = Int32.Parse(cont.Substring(split + 5));
cont.Remove(split);
Console.WriteLine("Value1: " + val1 + " Content: " + cont);
When I run this code, I get an Unhandled Exception which states Input string was not in a correct format, at System.Int32.Parse(String s), line 21. :(
So, my desired output should be
Value3: 1 Content: []val1:1val2:0
Value2: 0 Content: []val1:1
Value1: 1 Content: []
Your problem is in this code cont.Remove(split);
Strings are immutable, so you need to reassign new value.
In order to fix it you need to write
cont = cont.Remove(split);
You aren't putting the remove result back into the string, try doing this:
cont = cont.Remove(split);
When we perform some action on string it does not make changes in the same string instance. Instead it returns a new string instance. This concept is known as Immutability.
When you do
cont.Remove(split);
it does not update cont. Instead it returns updated string which you need to capture like this
cont = cont.Remove(split);
Restoring the cont value after calling the Remove method is missing.
Modified Code:
string cont = "[]val1:1val2:0val3:1";
int split = cont.IndexOf("val3:");
int val3 = Int32.Parse(cont.Substring(split + 5)); // this line successfully convert string to int
cont = cont.Remove(split);
Console.WriteLine("Value3: " + val3 + " Content: " + cont);
split = cont.IndexOf("val2:");
int val2 = Int32.Parse(cont.Substring(split + 5)); // but this line fails to convert from string to int..
cont = cont.Remove(split);
Console.WriteLine("Value2: " + val2 + " Content: " + cont);
split = cont.IndexOf("val1:");
int val1 = Int32.Parse(cont.Substring(split + 5));
cont = cont.Remove(split);
Console.WriteLine("Value1: " + val1 + " Content: " + cont);
Two ways you can fix the problem.
C# strings are immutable, so you have to modify your code to
cont = cont.Remove(split);
Another approach(might be best for your case), when using the SubString specify length, so you get specified number of characters.
split = cont.IndexOf("val2:");
int val2 = Int32.Parse(cont.Substring(split + 5, 1));
0val3:1 is not a valid number, therefore int.Parse fails. If you need to extract the 0 from the beginning of this string, you can refer to Parse an integer from a string with trailing garbage .
Also, the result of cont.Remove(split); is never used in your code snippet, and thus does nothing but waste CPU cycles. Considering you notice this behavior in the Console.WriteLine, and simply complain about an exception, I can only assume this was intentional?
Note that it looks like you're trying to extract key-value pairs from a string. A regular expression similar to val([^:]+):([0-9]+) might be a better tool here.
Alternatively, you can split on val and take the left/right of the colon. Something like:
var vals = cont.Split(new[] {"val"}, StringSplitOptions.None)
.Skip(1) //ignore any garbage at the beginning
.Select(x => x.Split(':'))
.ToDictionary(x => x[0], x => int.Parse(x[1]));
I have this little method to look for the 3-digit number in a string and increment it by one. The types of strings I am passing in are like CP1-P-CP2-004-D and MOT03-C-FP04-003.
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
foreach (char c in alphabet)
{
m = Regex.Match(s, #"\d{3}(?=[" + c + "-]|$)");
}
if (m.Success)
{
int i = Convert.ToInt32(m.Value); i += 1;
Console.WriteLine(s + " - " + i.ToString("D3"));
}
else { Console.WriteLine(s + " - No success"); }
EDIT: Initially I just had this; to test out my Regex.Match case:
Match m = Regex.Match(s, #"\d{3}(?=[A-]|$)");
And it worked with CP1PCP2001A no worries, but when I updated it, and tried CP1PCP2001C it returned "No Success", while CP1PCP2001 works no problem. Can anyone tell me why this is?
Have you tried
m = Regex.Match(s, #"\d{3}(?=[A-Z\-]|$)");
[A-Z] means that it can be any of the capital letters between A and Z thus eliminating the need for char[] alphabet, and the \- allows you to add the '-' as a parameter, without causing conflict with the first parameter.
From the comments, we're looking for "the first 3 digit number (coming from the right)". Here's a literal implementation:
m = Regex.Match(s, #"\d{3}", RegexOptions.RightToLeft);
This is more permissive towards unexpected characters than the other answers. You can decide whether that's good or bad for your application.
re-write the code this way
bool matched = false;
foreach (char c in alphabet)
{
m = Regex.Match(s, #"\d{3}(?=[" + c + "-]|$)");
if (m.Success)
{
int i = Convert.ToInt32(m.Value); i += 1;
Console.WriteLine(s + " - " + i.ToString("D3"));
matched=true;
break;
}
}
if(!matched)
Console.WriteLine(s + " - No success");
a better way would be not to loop and specify the char range to match in regex itself
example
m = Regex.Match(s, #"\d{3}(?=[A-Z\-]|$)");
if (m.Success)
{
int i = Convert.ToInt32(m.Value); i += 1;
Console.WriteLine(s + " - " + i.ToString("D3"));
}
else
Console.WriteLine(s + " - No success");
regex demo here
I search in a text for some strings and want to remove the first and last char in those strings.
Example :
...
...
OK 125 ab_D9 "can be "this" or; can not be "this" ";
...
OK 673 e_IO1_ "hello; is strong
or maybe not strong";
...
So I use the code to find all strings begin with OK and remove from the 4 groups "...":
tmp = fin.ReadToEnd();
var matches = Regex.Matches(tmp, "(OK) ([0-9]+) ([A-Za-z_0-9]+) (\"(?:(?!\";).)*\");", RegexOptions.Singleline);
for (int i = 0; i < matches.Count; i++)
{
matches[i].Groups[4].Value.Remove(0);
matches[i].Groups[4].Value.Remove(matches[i].Groups[4].Value.ToString().Length - 1);
Console.WriteLine(matches[i].Groups[1].Value + "\r\n" + "\r\n" + "\r\n" + matches[i].Groups[2].Value + "\r\n" + "\r\n" + matches[i].Groups[3].Value + "\r\n" + "\r\n" + "\r\n" + matches[i].Groups[4].Value);
Console.WriteLine(" ");
}
But it doesn't remove first and last char from Group 4. What did I do wrong?
My Result should be:
OK
125
ab_D9
can be "this" or; can not be "this"
OK
673
e_IO1
hello; is strong
or maybe not strong
There is no need to remove things. Just don't capture the quotes in the first place. So move the parentheses one character inward.
"(OK) ([0-9]+) ([A-Za-z_0-9]+) \"((?:(?!\";).)*)\";"
You should assign the result of Substring() and Remove() methods. they do not change the existing string but return the changed string which you need to assign to the same or some other string variable. Check the code:
tmp = fin.ReadToEnd();
var matches = Regex.Matches(tmp, "(OK) ([0-9]+) ([A-Za-z_0-9]+) (\"(?:(?!\";).)*\");", RegexOptions.Singleline);
for (int i = 0; i < matches.Count; i++)
{
string str = matches[i].Groups[4].Value.Substring(0);
str = str.Remove(str.Length - 1);
Console.WriteLine(matches[i].Groups[1].Value + "\r\n" + "\r\n" + "\r\n" + matches[i].Groups[2].Value + "\r\n" + "\r\n" + matches[i].Groups[3].Value + "\r\n" + "\r\n" + "\r\n" + str);
Console.WriteLine(" ");
}
P.S. You should use Environment.NewLine instead of "\r\n", it's the better approach.
I recived alarms in a form of text as the following
NE=JKHGDUWJ3 Alarm=Data Center STALZ AC Failure Occurrence=2012/4/3 22:18:19 GMT+02:00 Clearance=Details=Cabinet No.=0, Subrack No.=40, Slot No.=0, Port No.=5, Board Type=EDS, Site No.=49, Site Type=HSJYG500 GSM, Site Name=Google1 .
I need to fill it in csv file so later I can perform some analysis
I came up with this
if (!File.Exists(filesName)) {
string header = "NE,Alarm,Occurrence,Clearance,Details";
File.AppendAllText(filesName,header+Environment.NewLine);
}
StringBuilder sb = new StringBuilder();
string line = textBoxAlarm.Text;
int index = line.IndexOf(" ");
while (index > 0) {
string token = line.Substring(0, index).Trim();
line = line.Remove(0, index + 2);
string[] values = token.Split('=');
if (values.Length ==2) {
sb.Append(values[1] + ",");
} else {
if (values.Length % 2 == 0) {
string v = token
.Remove(0, values[0].Length + 1)
.Replace(',', ';');
sb.Append(v + ",");
} else {
sb.Append("********" + ",");
string v = token
.Remove(0, values[0].Length + 1 + values[1].Length + 1)
.Replace(',', ';');
sb.Append(v + ",");
}
}
index = line.IndexOf(" ");
}
File.AppendAllText(filesName, sb.ToString() + Environment.NewLine);
the results are as I want except when I reach the part of
Details=Cabinet No.=0, Subrack No.=40, Slot No.=0,
Port No.=5, Board Type=KDL, Site No.=49, Site Type=JDKJH99 GSM, Site Name=Google1 .
I couldnt split them into seperate fields.
as the results showing is as
I want to split the details I want each element in details to be in a column
to be somthin like
its realy annoying :-)
please help , thank you in advance
After this line:
string v = token.Remove(0, values[0].Length + 1 + values[1].Length + 1).Replace(',', ';')
Do:
var detailParts = v.Split(";".ToCharArray());
Now fill the detail parts. and append them to sb, for filling detail parts you need do something like this.
detailPart[i].Split("=".ToCharArrray())[1]
Split using this regex expression
string[] values = Regex.Split(line,
#",?\s*\w+(\sNo\.|\sType|\sName)?=",
RegexOptions.ExplicitCapture);
It should split the whole line at once. The only thing it cannot do, is to remove the " ." at the end of the line and it will also yield some unwanted entries
that you will have to remove (I marked them with a minus sign). This is what I get as result:
[0]-: ""
[1] : "JKHGDUWJ3"
[2] : "Data Center STALZ AC Failure"
[3] : "2012/4/3 22:18:19 GMT+02:00"
[4] : ""
[5]-: ""
[6] : "0"
[7] : "40"
[8] : "0"
[9] : "5"
[10] : "EDS"
[11] : "49"
[12] : "HSJYG500 GSM"
[13] : "Google1 ."
--
Let me explain the Regex expression ,?\s*\w+(\sNo\.|\sType|\sName)?=
,? an optional comma
\s*\w+ a word possibly preceded by spaces
(\sNo\.|\sType|\sName)? optionally a " No." or a " Type" or a " Name"
= an equal sign
UPDATE
The full code looks like this
if (!File.Exists(filesName)) {
string header = "NE,Alarm,Occurrence,Clearance,CabinetNo,SubrackNo,SlotNo,PortNo,BoardType,SiteNo,SiteType,SiteName";
File.AppendAllText(filesName, header + Environment.NewLine);
}
string line = textBoxAlarm.Text.TrimEnd(' ', '.');
string[] values = Regex.Split(line, #",?\s*\w+(\sNo\.|\sType|\sName)?=",
RegexOptions.ExplicitCapture);
List<string> valuesList = values.ToList();
valuesList.RemoveAt(5); // Remove the empty Details part.
valuesList.RemoveAt(0); // Remove the first empty part.
values = valuesList
.Select(s => s == "" ? "********" : s)
.ToArray();
File.AppendAllText(filesName, String.Join(",", values) + Environment.NewLine);