I am trying to spilt a string word into two strings based on the letter position. The two strings are even and odd. I manage to read the string and used a for loop but the conditional operator is not working and give me the error below. What did I do wrong?
Example: The string word is pole
Even position string - oe
Odd position string - pl
Error
Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
string word = Console.ReadLine();
for(int i = 0; i < word.Length; i++)
{
string even = "";
string odd = "";
((i % 2 == 0) ? even += word[i]: odd += word[i]);
}
You could use the discard operator as the following.
string word = Console.ReadLine();
string even = "";
string odd = "";
for(int i = 0; i < word.Length; i++)
{
var _ = ((i % 2 == 0) ? even += word[i]: odd += word[i]);
}
Couple of points to note here.
You need to declare the odd,even variables outside the loop, otherwise it would be recreated for each iteration of loop
Remember the string is immutable.You could also consider the StringBuilder class.
I am not that familiar with the ? operator, however, in my research, it appears it wants something like below…
((i % 2 == 0) ? ref even : ref odd) += word[i];
Unfortunately, even with this change, the even and odd variables are getting “reset” to empty with each iteration of the for loop with…
string even = "";
string odd = "";
If the goal is to concatenate the values, you do NOT want to create new even and odd variables with each iteration. So you should move those declarations “outside” the for loop. Something like…
string word = Console.ReadLine();
string even = "";
string odd = "";
for (int i = 0; i < word.Length; i++) {
((i % 2 == 0) ? ref even : ref odd) += word[i];
}
You use conditional operator to assign values inside of it. It is not allowed.
The correct for-loop is:
for (int i = 0; i < word.Length; i++)
{
if (i % 2 == 0)
{
even += word[i];
}
else
{
odd += word[i];
};
}
You can also use LINQ to get the expected result:
string word = Console.ReadLine();
string even = string.Concat(word.Where((c,i) => i % 2 == 0));
string odd = string.Concat(word.Where((c,i) => i % 2 == 1));
Online demo: https://dotnetfiddle.net/ePWHnp
Related
I think I am too dumb to solve this problem...
I have some formulas which need to be "translated" from one syntax to another.
Let's say I have a formula that goes like that (it's a simple one, others have many "Ceilings" in it):
string formulaString = "If([Param1] = 0, 1, Ceiling([Param2] / 0.55) * [Param3])";
I need to replace "Ceiling()" with "Ceiling(; 1)" (basically, insert "; 1" before the ")").
My attempt is to split the fomulaString at "Ceiling(" so I am able to iterate through the string array and insert my string at the correct index (counting every "(" and ")" to get the right index)
What I have so far:
//splits correct, but loses "CEILING("
string[] parts = formulaString.Split(new[] { "CEILING(" }, StringSplitOptions.None);
//splits almost correct, "CEILING(" is in another group
string[] parts = Regex.Split(formulaString, #"(CEILING\()");
//splits almost every letter
string[] parts = Regex.Split(formulaString, #"(?=[(CEILING\()])");
When everything is done, I concat the string so I have my complete formula again.
What do I have to set as Regex pattern to achieve this sample? (Or any other method that will help me)
part1 = "If([Param1] = 0, 1, ";
part2 = "Ceiling([Param2] / 0.55) * [Param3])";
//part3 = next "CEILING(" in a longer formula and so on...
As I mention in a comment, you almost got it: (?=Ceiling). This is incomplete for your use case unfortunately.
I need to replace "Ceiling()" with "Ceiling(; 1)" (basically, insert "; 1" before the ")").
Depending on your regex engine (for example JS) this works:
string[] parts = Regex.Split(formulaString, #"(?<=Ceiling\([^)]*(?=\)))");
string modifiedFormula = String.join("; 1", parts);
The regex
(?<=Ceiling\([^)]*(?=\)))
(?<= ) Positive lookbehind
Ceiling\( Search for literal "Ceiling("
[^)] Match any char which is not ")" ..
* .. 0 or more times
(?=\)) Positive lookahead for ")", effectively making us stop before the ")"
This regex is a zero-assertion, therefore nothing is lost and it will cut your strings before the last ")" in every "Ceiling()".
This solution would break whenever you have nested "Ceiling()". Then your only solution would be writing your own parser for the same reasons why you can't parse markup with regex.
Regex.Replace(formulaString, #"(?<=Ceiling\()(.*?)(?=\))","$1; 1");
Note: This will not work for nested "Ceilings", but it does for Ceiling(), It will also not work fir Ceiling(AnotherFunc(x)). For that you need something like:
Regex.Replace(formulaString, #"(?<=Ceiling\()((.*\((?>[^()]+|(?1))*\))*|[^\)]*)(\))","$1; 1$3");
but I could not get that to work with .NET, only in JavaScript.
This is my solution:
private string ConvertCeiling(string formula)
{
int ceilingsCount = formula.CountOccurences("Ceiling(");
int startIndex = 0;
int bracketCounter;
for (int i = 0; i < ceilingsCount; i++)
{
startIndex = formula.IndexOf("Ceiling(", startIndex);
bracketCounter = 0;
for (int j = 0; j < formula.Length; j++)
{
if (j < startIndex) continue;
var c = formula[j];
if (c == '(')
{
bracketCounter++;
}
if (c == ')')
{
bracketCounter--;
if (bracketCounter == 0)
{
// found end
formula = formula.Insert(j, "; 1");
startIndex++;
break;
}
}
}
}
return formula;
}
And CountOccurence:
public static int CountOccurences(this string value, string parameter)
{
int counter = 0;
int startIndex = 0;
int indexOfCeiling;
do
{
indexOfCeiling = value.IndexOf(parameter, startIndex);
if (indexOfCeiling < 0)
{
break;
}
else
{
startIndex = indexOfCeiling + 1;
counter++;
}
} while (true);
return counter;
}
My program needs to check for 3 consecutive letters in a string (and check through the whole string). I could make it check for them in a harcoded manner, like "check for qwe", "check for "wer", check for "ert", but that looks messy and badly done.
static void Main(string[] args)
{
string BadLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
for (int i = 1; i <= 30; i++)
{
// This checks if it contains "qwe" but i want it to
// cycle through the rest (such as "wer" or "rty")
if (password.Contains(BadLetters.Substring(0, 3))) {
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
Console.ReadKey();
}
The problem is that this only checks the first 3 letters of BadLetters (qwe), and it doesn't look for "ert", etc.
It would be better if you loop on the password variable instead, like this:
string badLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
for (int i = 0; i < password.Length-2; i++)
{
if (badLetters.Contains(password.Substring(i,3)))
{
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
Obviously you also have to check that the password is at least 3 characters.
This loop could fail on keyboard row crossing letters, i.e. "opa" or "pas", that should be considered right values, so you could do this instead:
string badLettersR1 = "qwertyuiop";
string badLettersR2 = "asdfghjkl";
string badLettersR3 = "zxcvbnm";
string password = "Blablauio";
for (int i = 0; i < password.Length-2; i++)
{
if (badLettersR1.Contains(password.Substring(i,3)) ||
badLettersR2.Contains(password.Substring(i,3)) ||
badLettersR3.Contains(password.Substring(i,3)))
{
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
Maybe you can try to edit your string, so the 3 letters are gone and then you do the same job as before for the next ones.
Or you can add to the 2 variables firstletter and secondletter 4 so it skips the first 3 as well and is repeating with the following ones
Sry i understood your string as 3 in a row...
You need to iterate through each character in password, find its index in BadLetters, and check if the next two characters in password match the next two in BadLetters. I also changed the stop condition of the for loop because you only need to iterate through the antepenultimate character in password
string BadLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
for (int i = 0; i < password.Length - 2; i++)
{
var j = BadLetters.IndexOf(password[i]);
if (j > -1 && j + 2 < BadLetters.Length &&
password[i + 1] == BadLetters[j + 1] &&
password[i + 2] == BadLetters[j + 2])
{
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
The simple one I found is
using System;
public class Program
{
public static void Main()
{
string BadLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
Console.WriteLine(password.IndexOf(BadLetters.Substring(0,3))>=0?"Present":"Not Present");
Console.ReadLine();
}
}
You may need to check for null condition of both strings
TL; DR
You could just go through array of symbols and compare it's indexes like this:
if (BadLetters.IndexOf(my_word[i]) - BadLetter.IndexOf(my_word[i-1]) == 1) {
Console.WriteLine("Consequent letters detected!");
}
you could just count consequent letters and alert when count more then 3
I provide detailed code with all lines from keyboard. And you could add another lines (i.e. upper case) without any modification of code.
You also have control on N - number of forbidden consequent characters in string.
Also there is Check method which using only for demonstrate results of working:
q - ok
qw - ok
qwe - password contains 3 consequtive letters in BadLetters
abdfsk - ok
ehjk - password contains 3 consequtive letters in BadLetters
bnm - password contains 3 consequtive letters in BadLetters
The code
Code on .net fiddle: https://dotnetfiddle.net/4oILkj
public static String[] KeyboardLines = new [] {
"1234567890",
"qwertyuiop[]",
"asdfghjkl;'\\",
"`zxcvbnm,./"
};
public static Int32 GetLine(char c){
for (int i = 0; i < KeyboardLines.Length; i++) {
if (KeyboardLines[i].IndexOf(c) > -1) {
return i;
};
}
return -1;
}
public static bool HasConsequenceLetters(string str, int n = 3) {
if (str.Length < n) {
return false;
}
char previousLetter = str[0];
int previousLine = GetLine(previousLetter);
int previousLetterIndex = KeyboardLines[previousLine].IndexOf(previousLetter);
Int32 consequentLettersCount = 1;
for (int i = 1; i < str.Length; i++) {
var currentLetter = str[i];
var currentLine = GetLine(currentLetter);
var currentLetterIndex = KeyboardLines[currentLine].IndexOf(currentLetter);
if (currentLine != -1 && currentLine == previousLine) {
if (currentLetterIndex - previousLetterIndex == 1) {
consequentLettersCount += 1;
}
}
else {
consequentLettersCount = 1;
}
if (consequentLettersCount == n) {
return true;
}
previousLetter = currentLetter;
previousLetterIndex = currentLetterIndex;
previousLine = currentLine;
}
return false;
}
Improvements
This approach could be improved if GetLine function will return character index with line number and then compare not just characters but pairs (LetterLine, LetterIndex). But this require from us to using tuples or classes but I don't think you really want this.
I've got a RichTextBox, here referred to as box.
string currentline = box.Lines[box.GetLineFromCharIndex(box.SelectionStart)];
That line there fetches the line the caret is in. It works excellently.
However, I have a need to get two strings from this. The first is everything on that line UP to the caret, and the second is everything on that line AFTER it.
For instance, if the line is How is you|r day going?, with | representing the caret, I would get How is you and r day going?, separately.
I wrote this monstrosity, which works:
string allbefore = box.Text.Substring(0, box.SelectionStart);
string allafter = box.Text.Substring(box.SelectionStart, box.Text.Length - box.SelectionStart);
string linebefore = "";
for (int i = 0; i < allbefore.Length; i++)
{
linebefore += allbefore[i];
if (allbefore[i] == '\n')
linebefore = "";
}
string lineafter = "";
for (int i = 0; i < allafter.Length; i++)
{
if (allafter[i] == '\n')
break;
else
lineafter += allafter[i];
}
It gives me the result I want, but involves looping through EVERY character in the entire box, which just hurts. Is there an easy way to do this I'm just missing? Thanks.
This might do the trick for you
string currentline = box.Lines[box.GetLineFromCharIndex(box.SelectionStart)];
var listOfStrings = new List<string>();
string[] splitedBox = currentline.Split('|');
foreach(string sp in splitedBox)
{
string[] lineleft = sp.Split('\n');
listOfStrings.Add(lineleft[lineleft.Count() - 1]);
}
In the first approach we are splitting the line by char | than finding if we have any \n if it exsist we are taking the values accordingly
Another approach could be
string box = "How is \n you|r day \n going?";
bool alllinesremoved = true;
while(alllinesremoved)
{
if(box.Contains('\n'))
{
if(box.IndexOf('\n') > box.IndexOf('|'))
{
box = box.Remove(box.IndexOf('\n'), (box.Length - box.IndexOf('\n')));
}
else
{
box = box.Remove(0, box.IndexOf('\n') + 1);
}
}
else
{
alllinesremoved = false;
}
}
string[] splitedBox = box.Split('|');
in the second approach we are removing the characters before and after the \n and then splitting the string. I think the second one seems more good to me.
Have you tried using line.split? Not sure if this is what you want.
Store the position of \n using indexOf and, if >= 0, that is, the string contains it, use substring and assign the value otherwise.
string allbefore = box.Text.Substring(0, box.SelectionStart);
string allafter = box.Text.Substring(box.SelectionStart, box.Text.Length - box.SelectionStart);
int newLinePos = allBefore.lastIndexOf("\n");
string lineBefore = ((newLinePos >= 0) ? (allBefore.substring(newLinePos + 1)) : (allBefore));
newLinePos = allafter.indexOf("\n");
string lineAfter = ((newLinePost >= 0) ? (allAfter.substring(0, newLinePos)) : (allAfter));
I am trying to extract information out of a string - a fortran formatting string to be specific. The string is formatted like:
F8.3, I5, 3(5X, 2(A20,F10.3)), 'XXX'
with formatting fields delimited by "," and formatting groups inside brackets, with the number in front of the brackets indicating how many consecutive times the formatting pattern is repeated. So, the string above expands to:
F8.3, I5, 5X, A20,F10.3, A20,F10.3, 5X, A20,F10.3, A20,F10.3, 5X, A20,F10.3, A20,F10.3, 'XXX'
I am trying to make something in C# that will expand a string that conforms to that pattern. I have started going about it with lots of switch and if statements, but am wondering if I am not going about it the wrong way?
I was basically wondering if some Regex wizzard thinks that Regular expressions can do this in one neat-fell swoop? I know nothing about regular expressions, but if this could solve my problem I am considering putting in some time to learn how to use them... on the other hand if regular expressions can't sort this out then I'd rather spend my time looking at another method.
This has to be doable with Regex :)
I've expanded my previous example and it test nicely with your example.
// regex to match the inner most patterns of n(X) and capture the values of n and X.
private static readonly Regex matcher = new Regex(#"(\d+)\(([^(]*?)\)", RegexOptions.None);
// create new string by repeating X n times, separated with ','
private static string Join(Match m)
{
var n = Convert.ToInt32(m.Groups[1].Value); // get value of n
var x = m.Groups[2].Value; // get value of X
return String.Join(",", Enumerable.Repeat(x, n));
}
// expand the string by recursively replacing the innermost values of n(X).
private static string Expand(string text)
{
var s = matcher.Replace(text, Join);
return (matcher.IsMatch(s)) ? Expand(s) : s;
}
// parse a string for occurenses of n(X) pattern and expand then.
// return the string as a tokenized array.
public static string[] Parse(string text)
{
// Check that the number of parantheses is even.
if (text.Sum(c => (c == '(' || c == ')') ? 1 : 0) % 2 == 1)
throw new ArgumentException("The string contains an odd number of parantheses.");
return Expand(text).Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
I would suggest using a recusive method like the example below( not tested ):
ResultData Parse(String value, ref Int32 index)
{
ResultData result = new ResultData();
Index startIndex = index; // Used to get substrings
while (index < value.Length)
{
Char current = value[index];
if (current == '(')
{
index++;
result.Add(Parse(value, ref index));
startIndex = index;
continue;
}
if (current == ')')
{
// Push last result
index++;
return result;
}
// Process all other chars here
}
// We can't find the closing bracket
throw new Exception("String is not valid");
}
You maybe need to modify some parts of the code, but this method have i used when writing a simple compiler. Although it's not completed, just a example.
Personally, I would suggest using a recursive function instead. Every time you hit an opening parenthesis, call the function again to parse that part. I'm not sure if you can use a regex to match a recursive data structure.
(Edit: Removed incorrect regex)
Ended up rewriting this today. It turns out that this can be done in one single method:
private static string ExpandBrackets(string Format)
{
int maxLevel = CountNesting(Format);
for (int currentLevel = maxLevel; currentLevel > 0; currentLevel--)
{
int level = 0;
int start = 0;
int end = 0;
for (int i = 0; i < Format.Length; i++)
{
char thisChar = Format[i];
switch (Format[i])
{
case '(':
level++;
if (level == currentLevel)
{
string group = string.Empty;
int repeat = 0;
/// Isolate the number of repeats if any
/// If there are 0 repeats the set to 1 so group will be replaced by itself with the brackets removed
for (int j = i - 1; j >= 0; j--)
{
char c = Format[j];
if (c == ',')
{
start = j + 1;
break;
}
if (char.IsDigit(c))
repeat = int.Parse(c + (repeat != 0 ? repeat.ToString() : string.Empty));
else
throw new Exception("Non-numeric character " + c + " found in front of the brackets");
}
if (repeat == 0)
repeat = 1;
/// Isolate the format group
/// Parse until the first closing bracket. Level is decremented as this effectively takes us down one level
for (int j = i + 1; j < Format.Length; j++)
{
char c = Format[j];
if (c == ')')
{
level--;
end = j;
break;
}
group += c;
}
/// Substitute the expanded group for the original group in the format string
/// If the group is empty then just remove it from the string
if (string.IsNullOrEmpty(group))
{
Format = Format.Remove(start - 1, end - start + 2);
i = start;
}
else
{
string repeatedGroup = RepeatString(group, repeat);
Format = Format.Remove(start, end - start + 1).Insert(start, repeatedGroup);
i = start + repeatedGroup.Length - 1;
}
}
break;
case ')':
level--;
break;
}
}
}
return Format;
}
CountNesting() returns the highest level of bracket nesting in the format statement, but could be passed in as a parameter to the method. RepeatString() just repeats a string the specified number of times and substitutes it for the bracketed group in the format string.
Not entirely sure this is possible, but say I have two strings like so:
"IAmAString-00001"
"IAmAString-00023"
What would be a quick'n'easy way to iterate from IAmAString-0001 to IAmAString-00023 by moving up the index of just the numbers on the end?
The problem is a bit more general than that, for example the string I could be dealing could be of any format but the last bunch of chars will always be numbers, so something like Super_Confusing-String#w00t0003 and in that case the last 0003 would be what I'd use to iterate through.
Any ideas?
You can use char.IsDigit:
static void Main(string[] args)
{
var s = "IAmAString-00001";
int index = -1;
for (int i = 0; i < s.Length; i++)
{
if (char.IsDigit(s[i]))
{
index = i;
break;
}
}
if (index == -1)
Console.WriteLine("digits not found");
else
Console.WriteLine("digits: {0}", s.Substring(index));
}
which produces this output:
digits: 00001
string.Format and a for loop should do what you want.
for(int i = 0; i <=23; i++)
{
string.Format("IAmAString-{0:D4}",i);
}
or something close to that (not sitting in front of a compiler).
string start = "IAmAString-00001";
string end = "IAmAString-00023";
// match constant part and ending digits
var matchstart = Regex.Match(start,#"^(.*?)(\d+)$");
int numberstart = int.Parse(matchstart.Groups[2].Value);
var matchend = Regex.Match(end,#"^(.*?)(\d+)$");
int numberend = int.Parse(matchend.Groups[2].Value);
// constant parts must be the same
if (matchstart.Groups[1].Value != matchend.Groups[1].Value)
throw new ArgumentException("");
// create a format string with same number of digits as original
string format = new string('0', matchstart.Groups[2].Length);
for (int ii = numberstart; ii <= numberend; ++ii)
Console.WriteLine(matchstart.Groups[1].Value + ii.ToString(format));
You could use a Regex:
var match=Regex.Match("Super_Confusing-String#w00t0003",#"(?<=(^.*\D)|^)\d+$");
if(match.Success)
{
var val=int.Parse(match.Value);
Console.WriteLine(val);
}
To answer more specifically, you could use named groups to extract what you need:
var match=Regex.Match(
"Super_Confusing-String#w00t0003",
#"(?<prefix>(^.*\D)|^)(?<digits>\d+)$");
if(match.Success)
{
var prefix=match.Groups["prefix"].Value;
Console.WriteLine(prefix);
var val=int.Parse(match.Groups["digits"].Value);
Console.WriteLine(val);
}
If you can assume that the last 5 characters are the number then:
string prefix = "myprefix-";
for (int i=1; i <=23; i++)
{
Console.WriteLine(myPrefix+i.ToString("D5"));
}
This function will find the trailing number.
private int FindTrailingNumber(string str)
{
string numString = "";
int numTest;
for (int i = str.Length - 1; i > 0; i--)
{
char c = str[i];
if (int.TryParse(c.ToString(), out numTest))
{
numString = c + numString;
}
}
return int.Parse(numString);
}
Assuming all your base strings are the same, this would iterate between strings.
string s1 = "asdf123";
string s2 = "asdf127";
int num1 = FindTrailingNumber(s1);
int num2 = FindTrailingNumber(s2);
string strBase = s1.Replace(num1.ToString(), "");
for (int i = num1; i <= num2; i++)
{
Console.WriteLine(strBase + i.ToString());
}
I think it would be better if you do the search from the last (Rick already upvoted you since it was ur logic :-))
static void Main(string[] args)
{
var s = "IAmAString-00001";
int index = -1;
for (int i = s.Length - 1; i >=0; i--)
{
if (!char.IsDigit(s[i]))
{
index = i;
break;
}
}
if (index == -1)
Console.WriteLine("digits not found");
else
Console.WriteLine("digits: {0}", s.Substring(index));
Console.ReadKey();
}
HTH
If the last X numbers are always digits, then:
int x = 5;
string s = "IAmAString-00001";
int num = int.Parse(s.Substring(s.Length - x, x));
Console.WriteLine("Your Number is: {0}", num);
If the last digits can be 3, 4, or 5 in length, then you will need a little more logic:
int x = 0;
string s = "IAmAString-00001";
foreach (char c in s.Reverse())//Use Reverse() so you start with digits only.
{
if(char.IsDigit(c) == false)
break;//If we start hitting non-digit characters, then exit the loop.
++x;
}
int num = int.Parse(s.Substring(s.Length - x, x));
Console.WriteLine("Your Number is: {0}", num);
I'm not good with complicated RegEx. Because of this, I always shy away from it when maximum optimization is unnecessary. The reason for this is RegEx doesn't always parse strings the way you expect it to. If there is and alternate solution that will still run fast then I'd rather go that route as it's easier for me to understand and know that it will work with any combination of strings.
For Example: if you use some of the other solutions presented here with a string like "I2AmAString-000001", then you will get "2000001" as your number instead of "1".