After extensive debugging of an application, I noticed the console window would hang when searching text for the char '\a'. The goal is to strip out characters from a file. The below portion just prints the stripped output. It causes the same issue.
The console window would always hang upon exiting the program, and it would make it to the last statement of main. I removed the '\a' from the switch statement and the console application does not hang anymore. Any idea why? I still need to strip out the char '\a', but cannot get the application to work without hanging.
static void Main(string[] args)
{
string s_filename = args[0];
Read(s_filename, 0);
}
static void Read(string s_filename, int i_char)
{
try
{
char ch;
StringBuilder sb = new StringBuilder();
using (FileStream fs = new FileStream(s_filename, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs))
{
for (int i = 0; i < fs.Length; i++)
{
byte b_byte = br.ReadByte(); //Reads the bytes one at a time.
ch = (char)(b_byte);
if (isString(ch, i_char) || (sb.Length > 0 && ch == ' '))
sb.Append(ch);
else
{
if (sb.Length == 0)
continue;
if (sb.Length >= 4)
{
Console.WriteLine(sb);
}
sb.Length = 0;
}
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Error {0}", e);
}
}
static bool isString(char c, int i) //http://msdn.microsoft.com/en-us/library/h21280bw.aspx
{
if (i == 0)
{
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= '0' && c <= '9')
return true;
switch (c)
{
case '~':
case '`':
case '!':
case '#':
case '#':
case '$':
case '%':
case '^':
case '&':
case '*':
case '(':
case ')':
case '-':
case '_':
case '+':
case '=':
case '[':
case ']':
case '{':
case '}':
case '|':
case '\\':
case ';':
case ':':
case '"':
case '\'':
case '<':
case '>':
case ',':
case '.':
case '?':
case '/':
case '\t': //Horizontal Tab
case '\v': //Vertical Tab
case '\n': //Newline
case '\f'://Formfeed
case '\r': //carriage return
case '\b': //Backspace
case '\x7f': //delete character
case '\x99': //TM Trademark
case '\a': //Bell Alert
return true;
}
}
if (i == 1)
{
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= '0' && c <= '9')
return true;
switch (c)
{
case '~':
case '`':
case '!':
case '#':
case '#':
case '$':
case '%':
case '^':
case '&':
case '*':
case '(':
case ')':
case '-':
case '_':
case '+':
case '=':
case '[':
case ']':
case '{':
case '}':
case '|':
case '\\':
case ';':
case ':':
case '"':
case '\'':
case '<':
case '>':
case ',':
case '.':
case '?':
case '/':
return true;
}
}
if (i == 2)
{
if (Char.IsLetterOrDigit(c))
return true;
switch (c)
{
case '~':
case '`':
case '!':
case '#':
case '#':
case '$':
case '%':
case '^':
case '&':
case '*':
case '(':
case ')':
case '-':
case '_':
case '+':
case '=':
case '[':
case ']':
case '{':
case '}':
case '|':
case '\\':
case ';':
case ':':
case '"':
case '\'':
case '<':
case '>':
case ',':
case '.':
case '?':
case '/':
return true;
}
}
if (i == 3)
{
if (Char.IsLetterOrDigit(c))
return true;
switch (c)
{
case '~':
case '`':
case '!':
case '#':
case '#':
case '$':
case '%':
case '^':
case '&':
case '*':
case '(':
case ')':
case '-':
case '_':
case '+':
case '=':
case '[':
case ']':
case '{':
case '}':
case '|':
case '\\':
case ';':
case ':':
case '"':
case '\'':
case '<':
case '>':
case ',':
case '.':
case '?':
case '/':
case '\t': //Horizontal Tab
case '\v': //Vertical Tab
case '\n': //Newline
case '\f'://Formfeed
case '\r': //carriage return
case '\b': //Backspace
case '\x7f': //delete character
case '\x99': //TM Trademark
case '\a': //Bell Alert
return true;
}
}
if (i == 4)
{
if (Char.IsLetterOrDigit(c))
return true;
}
if (i == 5)
{
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= '0' && c <= '9')
return true;
}
return false;
}
I don't see why your program would hang, but you haven't given us much to go on.
Maybe try replacing the '\a' with a literal 7.
See also http://asciitable.com/ for other character codes.
But I'm thinking it has to do with some other program logic, not just the '\a' in your code.
Anyway, that seems to me a better approach - try to rework your code if applicable:
using System.Linq;
bool Contains(string input)
{
var arr = new[] { '\t', '\v', '\n', '\f', '\r', '\b', '\x7f', '\x99', '\a', .. };
return arr.Any(c => input.Contains(c));
}
Related
I want to be able to pass upperEncodedMsg into the text property of msgLabel at the bottom of my code.
namespace ProgrammingAssignmentDecoder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Encode()
{
string message = Convert.ToString(messageTxt.Text);
char[] encodeArray = message.ToCharArray();
for (int i = 0; i < encodeArray.Length; i++)
{
char letter = (encodeArray[i]);
switch (letter)
{
case 'a':
case 'A':
encodeArray[i] = 't';
break;
case 'b':
case 'B':
encodeArray[i] = 'u';
break;
case 'c':
case 'C':
encodeArray[i] = 'v';
break;
case 'd':
case 'D':
encodeArray[i] = 'w';
break;
case 'e':
case 'E':
encodeArray[i] = 'x';
break;
case 'f':
case 'F':
encodeArray[i] = 'y';
break;
case 'g':
case 'G':
encodeArray[i] = 'z';
break;
case 'h':
case 'H':
encodeArray[i] = 'a';
break;
case 'i':
case 'I':
encodeArray[i] = 'b';
break;
case 'j':
case 'J':
encodeArray[i] = 'c';
break;
case 'k':
case 'K':
encodeArray[i] = 'd';
break;
case 'l':
case 'L':
encodeArray[i] = 'e';
break;
case 'm':
case 'M':
encodeArray[i] = 'f';
break;
case 'n':
case 'N':
encodeArray[i] = 'g';
break;
case 'o':
case 'O':
encodeArray[i] = 'h';
break;
case 'p':
case 'P':
encodeArray[i] = 'i';
break;
case 'q':
case 'Q':
encodeArray[i] = 'j';
break;
case 'r':
case 'R':
encodeArray[i] = 'k';
break;
case 's':
case 'S':
encodeArray[i] = 'l';
break;
case 't':
case 'T':
encodeArray[i] = 'm';
break;
case 'u':
case 'U':
encodeArray[i] = 'n';
break;
case 'v':
case 'V':
encodeArray[i] = 'o';
break;
case 'w':
case 'W':
encodeArray[i] = 'p';
break;
case 'x':
case 'X':
encodeArray[i] = 'q';
break;
case 'y':
case 'Y':
encodeArray[i] = 'r';
break;
case 'z':
case 'Z':
encodeArray[i] = 's';
break;
}
}
}
static string upperEncoded(char[] encodeArray, string upperEncodedMsg)
{
string encodedMsg = new string(encodeArray);
upperEncodedMsg = encodedMsg.ToUpper();
return upperEncodedMsg;
}
private void clearBtn_Click(object sender, EventArgs e)
{
messageTxt.Text = string.Empty;
msgLabel.Text = string.Empty;
processedMessageLabel.Text = "Processed Message: ";
}
private void encodeBtn_Click(object sender, EventArgs e)
{
Encode();
if (messageTxt.TextLength == 0)
{
MessageBox.Show("There is no message to Encode");
}
else
{
processedMessageLabel.Text = "Encoded Message: ";
msgLabel.Visible = true;
}
msgLabel.Text = upperEncodedMsg;
}
}
}
I tried to keep your structure in tact, there are a few things that could be done in less characters and in less complicated ways, but as you are learning the language practice is the only thing that can improve your skills :) So well done.
namespace ProgrammingAssignmentDecoder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private string upperEncodedMsg = null;
public void Encode()
{
string message = Convert.ToString(messageTxt.Text);
char[] encodeArray = message.ToCharArray();
for (int i = 0; i < encodeArray.Length; i++)
{
char letter = (encodeArray[i]);
switch (letter)
{
case 'a':
case 'A':
encodeArray[i] = 't';
break;
case 'b':
case 'B':
encodeArray[i] = 'u';
break;
case 'c':
case 'C':
encodeArray[i] = 'v';
break;
case 'd':
case 'D':
encodeArray[i] = 'w';
break;
case 'e':
case 'E':
encodeArray[i] = 'x';
break;
case 'f':
case 'F':
encodeArray[i] = 'y';
break;
case 'g':
case 'G':
encodeArray[i] = 'z';
break;
case 'h':
case 'H':
encodeArray[i] = 'a';
break;
case 'i':
case 'I':
encodeArray[i] = 'b';
break;
case 'j':
case 'J':
encodeArray[i] = 'c';
break;
case 'k':
case 'K':
encodeArray[i] = 'd';
break;
case 'l':
case 'L':
encodeArray[i] = 'e';
break;
case 'm':
case 'M':
encodeArray[i] = 'f';
break;
case 'n':
case 'N':
encodeArray[i] = 'g';
break;
case 'o':
case 'O':
encodeArray[i] = 'h';
break;
case 'p':
case 'P':
encodeArray[i] = 'i';
break;
case 'q':
case 'Q':
encodeArray[i] = 'j';
break;
case 'r':
case 'R':
encodeArray[i] = 'k';
break;
case 's':
case 'S':
encodeArray[i] = 'l';
break;
case 't':
case 'T':
encodeArray[i] = 'm';
break;
case 'u':
case 'U':
encodeArray[i] = 'n';
break;
case 'v':
case 'V':
encodeArray[i] = 'o';
break;
case 'w':
case 'W':
encodeArray[i] = 'p';
break;
case 'x':
case 'X':
encodeArray[i] = 'q';
break;
case 'y':
case 'Y':
encodeArray[i] = 'r';
break;
case 'z':
case 'Z':
encodeArray[i] = 's';
break;
}
}
foreach (char eachChar in encodeArray) {
upperEncodedMsg += eachChar;
}
}
public void upperEncoded()
{
if (upperEncodedMsg != null)
{ upperEncodedMsg = upperEncodedMsg.ToUpper(); }
}
private void clearBtn_Click(object sender, EventArgs e)
{
messageTxt.Text = string.Empty;
msgLabel.Text = string.Empty;
processedMessageLabel.Text = "Processed Message: ";
}
private void encodeBtn_Click(object sender, EventArgs e)
{
if (messageTxt.TextLength == 0)
{
MessageBox.Show("There is no message to Encode");
}
else
{
Encode();
upperEncoded();
processedMessageLabel.Text = "Encoded Message: ";
msgLabel.Visible = true;
}
msgLabel.Text = upperEncodedMsg;
}
}
}
I'd go down the route of creating a mapping using a Dictionary<char, char>(see here for details on Dictionary) and simply lookup the key value in the dictionary for each char in encodeArray. It may also be better to use a StringBuilder rather than just a string to store your encoded message.
Create Mapping
//Add Dictionary at the top of the class along with upperEncodedMsg string.
private Dictionary<char, char> charMapping;
private StringBuilder upperEncodedMsg;
//Create mappings. Use uppercase values here and you won't need to use your 'upperEncoded' method. This bit can be done in your Form1 constructor.
public Form1()
{
InitializeComponent();
charMapping = new Dictionary<char, char>();
charMapping.Add('A', 'T');
charMapping.Add('B', 'U');
//more mappings...
}
You can then remove the big switch statement you have and replace it with the following:
public void Encode()
{
upperEncodedMsg = new StringBuilder();
string message = Convert.ToString(messageTxt.Text);
char[] encodeArray = message.ToUpper().ToCharArray();
for(int i = 0; i < encodeArray.Length; i++)
{
//Use the mappings created earlier to get the associated char.
char outputLetter;
charMapping.TryGetValue(encodeArray[i], out outputLetter);
//Append letter to your upperEncodedMsg StringBuilder.
upperEncodedMsg.Append(outputLetter);
}
}
In your button click, at the bottom you can then add:
private void encodeBtn_Click(object sender, EventArgs e)
{
//your code...
msgLabel.Text = upperEncodedMsg.ToString();
}
The main benefit of doing it this way is that your mappings can be made available in other parts of your code. It also makes it easier to maintain and your mappings are loaded as soon as the form is, rather than waiting to call your encode method. A lookup of a Dictionary is also likely to be quicker than a large switch statement.
Actually this post is different from this (posted by me as well). I've a phone keypad in my UI and now I'm able to show the button is pressed when its corresponding key is down.
private void NumDisplayBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.D0:
case Key.NumPad0:
ZeroBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D1:
case Key.NumPad1:
OneBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D2:
case Key.NumPad2:
TwoBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D3:
case Key.NumPad3:
ThreeBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D4:
case Key.NumPad4:
FourBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D5:
case Key.NumPad5:
FiveBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D6:
case Key.NumPad6:
SixBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D7:
case Key.NumPad7:
SevenBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D8:
case Key.NumPad8:
EightBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D9:
case Key.NumPad9:
NineBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
}
if (((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift))
{
if (e.Key == Key.D3)
{
ThreeBtn.Style = (Style)FindResource("NormalButtonStyle");
HashBtn.Style = (Style)FindResource("PressedButtonStyle");
}
}
}
private void NumDisplayBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.D0:
case Key.NumPad0:
ZeroBtn.Style = (Style) FindResource("ButtonStyle4"); break;
case Key.D1:
case Key.NumPad1:
OneBtn.Style = (Style) FindResource("ButtonStyle4"); break;
.
.
.
}
}
The problem is when hash key (Shift + 3) or star key (Shift + 8) is down, the '3' button (for case hash key) also be pressed in UI. How can I show that only hash button is pressed on UI when Shift + 3 are down, but not hash button together with '3' button?
Check the KeyEventArgs.Modifiers property, and only handle the key-down when no modifiers are set.
Alternatively, use the TextInput or PreviewTextInput event to get the composed text instead of the actual key. This may be preferable anyway, as it will respond to any method of entering the appropriate text input, rather than relying on a specific key (for example, you won't have to have cases for all the possible keys, such as the top-row numeric keys and the numeric pad keys, as you are now).
This works for me:
//Make the button to have "pressed" feel when the corresponding key is pressed
private void NumDisplayBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift))
{
if (e.Key == Key.D3)
HashBtn.Style = (Style) FindResource("PressedButtonStyle");
if (e.Key == Key.D8)
StarBtn.Style = (Style) FindResource("PressedButtonStyle");
}
switch (e.Key)
{
case Key.D0:
case Key.NumPad0:
ZeroBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D1:
case Key.NumPad1:
OneBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D2:
case Key.NumPad2:
TwoBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D3:
case Key.NumPad3:
{
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
ThreeBtn.Style = (Style) FindResource("ButtonStyle4");
else
ThreeBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
}
case Key.D4:
case Key.NumPad4:
FourBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D5:
case Key.NumPad5:
FiveBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D6:
case Key.NumPad6:
SixBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D7:
case Key.NumPad7:
SevenBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D8:
case Key.NumPad8:
{
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
EightBtn.Style = (Style) FindResource("ButtonStyle4");
else
EightBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
}
case Key.D9:
case Key.NumPad9:
NineBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
default:
break;
}
}
//Return back to its original style
private void NumDisplayBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.D0:
case Key.NumPad0:
ZeroBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D1:
case Key.NumPad1:
OneBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D2:
case Key.NumPad2:
TwoBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D3:
case Key.NumPad3:
ThreeBtn.Style = (Style) FindResource("ButtonStyle4");
HashBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D4:
case Key.NumPad4:
FourBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D5:
case Key.NumPad5:
FiveBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D6:
case Key.NumPad6:
SixBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D7:
case Key.NumPad7:
SevenBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D8:
case Key.NumPad8:
EightBtn.Style = (Style) FindResource("ButtonStyle4");
StarBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D9:
case Key.NumPad9:
NineBtn.Style = (Style) FindResource("ButtonStyle4");
break;
default:
break;
}
}
I have a program that generates C# from bits of C# stored in an XML file. If I have a snippet like:
foo {bar}
I need to transform that into an interpolated string, like this:
$#"foo {bar}"
The problem is that, if I have quotes outside a placeholder, e.g.:
"foo" {bar}
I need to double those:
$#"""foo"" {bar}"
but ignore quotes inside placeholders:
foo {"bar"}
should produce:
$#"foo {"bar"}"
Also, need to look out for doubled braces:
foo {{"bar"}}
should produce:
$#"foo {{""bar""}}"
And perhaps the trickiest of all, if the placeholder is preceded and/or followed by an even number of braces:
foo {{{"bar"}}}
should produce:
$#"foo {{{"bar"}}}"
In short, if there's a placeholder then ignore everything inside. For the rest of the text, double quotes.
Can this be accomplished using regular expressions? If not, what alternatives do I have?
You will need at least 2 steps:
Add quotes inside the expression:
"(?=[^}]*(?:}})*[^}]*$)|(?<=^[^{]*(?:{{)*)" =>
replace with ""
See demo
Enclose in $#"..." with string.Format("$#\"{0}\"", str);
Here is an IDEONE demo
var s = "\"foo\" {bar}";
var rx = new Regex(#"(?<!(?<!{){[^{}]*)""(?![^{}]*}(?!}))");
Console.WriteLine(string.Format("$#\"{0}\"",rx.Replace(s,"\"\"")));
And another demo here
This cannot be done with regular expressions. Knowing when a placeholder starts is easy, knowing when it ends is the hard part, since a placeholder can hold almost any C# expression, so you have to keep track of blocks ({}) and literals (strings, chars, comments) because any brace in a literal is not significant.
This is the code I came up with:
enum ParsingMode {
Text,
Code,
InterpolatedString,
InterpolatedVerbatimString,
String,
VerbatimString,
Char,
MultilineComment
}
public static string EscapeValueTemplate(string valueTemplate) {
if (valueTemplate == null) throw new ArgumentNullException(nameof(valueTemplate));
var quoteIndexes = new List<int>();
var modeStack = new Stack<ParsingMode>();
modeStack.Push(ParsingMode.Text);
Func<ParsingMode> currentMode = () => modeStack.Peek();
for (int i = 0; i < valueTemplate.Length; i++) {
char c = valueTemplate[i];
Func<char?> nextChar = () =>
i + 1 < valueTemplate.Length ? valueTemplate[i + 1]
: default(char?);
switch (currentMode()) {
case ParsingMode.Code:
switch (c) {
case '{':
modeStack.Push(ParsingMode.Code);
break;
case '}':
modeStack.Pop();
break;
case '\'':
modeStack.Push(ParsingMode.Char);
break;
case '"':
ParsingMode stringMode = ParsingMode.String;
switch (valueTemplate[i - 1]) {
case '#':
if (i - 2 >= 0 && valueTemplate[i - 2] == '$') {
stringMode = ParsingMode.InterpolatedVerbatimString;
} else {
stringMode = ParsingMode.VerbatimString;
}
break;
case '$':
stringMode = ParsingMode.InterpolatedString;
break;
}
modeStack.Push(stringMode);
break;
case '/':
if (nextChar() == '*') {
modeStack.Push(ParsingMode.MultilineComment);
i++;
}
break;
}
break;
case ParsingMode.Text:
case ParsingMode.InterpolatedString:
case ParsingMode.InterpolatedVerbatimString:
switch (c) {
case '{':
if (nextChar() == '{') {
i++;
} else {
modeStack.Push(ParsingMode.Code);
}
break;
case '"':
switch (currentMode()) {
case ParsingMode.Text:
quoteIndexes.Add(i);
break;
case ParsingMode.InterpolatedString:
modeStack.Pop();
break;
case ParsingMode.InterpolatedVerbatimString:
if (nextChar() == '"') {
i++;
} else {
modeStack.Pop();
}
break;
}
break;
case '\\':
if (currentMode() == ParsingMode.InterpolatedString) {
i++;
}
break;
}
break;
case ParsingMode.String:
switch (c) {
case '\\':
i++;
break;
case '"':
modeStack.Pop();
break;
}
break;
case ParsingMode.VerbatimString:
if (c == '"') {
if (nextChar() == '"') {
i++;
} else {
modeStack.Pop();
}
}
break;
case ParsingMode.Char:
switch (c) {
case '\\':
i++;
break;
case '\'':
modeStack.Pop();
break;
}
break;
case ParsingMode.MultilineComment:
if (c == '*') {
if (nextChar() == '/') {
modeStack.Pop();
i++;
}
}
break;
}
}
var sb = new StringBuilder(valueTemplate, valueTemplate.Length + quoteIndexes.Count);
for (int i = 0; i < quoteIndexes.Count; i++) {
sb.Insert(quoteIndexes[i] + i, '"');
}
return sb.ToString();
}
My application works if I type in 1 character, such as A. It will give me 10 2's,
but I want it to work on all 10 digits I type in. What am I doing wrong?
I want it so I can type in 1800HELLO2 and it will give me all digits.
class Program
{
static void Main(string[] args)
{
int x = 0;
string userInput;
Console.WriteLine("Please enter the 10 digit telephone number. ");
userInput = Console.ReadLine();
while (x < 10)
{
switch (userInput)
{
case "1":
userInput = "1";
x++;
break;
case "A":
case "B":
case "C":
case "2":
userInput = "2";
x++;
break;
case "D":
case "E":
case "F":
case "3":
userInput = "3";
x++;
break;
case "G":
case "H":
case "I":
case "4":
userInput = "4";
x++;
break;
case "J":
case "K":
case "L":
case "5":
userInput = "5";
x++;
break;
case "M":
case "N":
case "O":
case "6":
userInput = "6";
x++;
break;
case "P":
case "Q":
case "R":
case "7":
userInput = "7";
x++;
break;
case "S":
case "T":
case "U":
case "8":
userInput = "8";
x++;
break;
case "V":
case "W":
case "X":
case "Y":
case "Z":
userInput = "9";
x++;
break;
case "0":
userInput = "0";
break;
}
Console.WriteLine(userInput);
}
}
}
}
Your user input can be any number of characters (the ReadLine() function will read N characters until you press ENTER) but your switch statement doesn't check individual characters of your input - it only checks a number of 1-character strings.
This means that even if you type 1-800-333-1111, you'll never check it because it's not a 1-character string like the various cases you have in the switch.
You need to iterate through each character one-by-one in the input string and check the individual characters. For example:
if ( userinput != null )
{
userinput = userinput.ToUpper ();
for ( int i = 0; i < userinput.Length; i++ )
{
switch ( userinput[i] )
{
case '1':
case 'A':
...
break;
...
default:
// Handle invalid characters here
break;
}
}
}
Notice that the various case values are single characters (using the '), not 1-character strings.
Do note, that it's not a very good idea to hardcode the length of the phone number as a number in the code. Different users may enter the phone numbers differently - some may use spaces or dashes as separators, some may only enter the digit. In these cases the length of the input string will be different. Some users may even accidentally enter multiple spaces or put in ( and ) for the area code.
You should validate the input before you even check or you shouldn't rely on the number of input digits as you iterate through the input.
Your approach isn't really correct. You're switching on userInput every time, when really you want to check each character in the string. Study the code below:
using System;
class Program {
static void Main(string[] args) {
Console.WriteLine("Please enter the 10 digit telephone number. ");
string userInput = Console.ReadLine();
// Maybe do some validation here, check the length etc
Char output;
foreach (Char c in userInput) {
switch (c) {
case 'A':
case 'B':
case 'C':
output = '2';
break;
case 'D':
case 'E':
case 'F':
output = '3';
break;
case 'G':
case 'H':
case 'I':
output = '4';
break;
case 'J':
case 'K':
case 'L':
output = '5';
break;
case 'M':
case 'N':
case 'O':
output = '6';
break;
case 'P':
case 'Q':
case 'R':
output = '7';
break;
case 'S':
case 'T':
case 'U':
output = '8';
break;
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
output = '9';
break;
default:
output = c;
break;
}
Console.Write(output);
}
Console.WriteLine();
Console.ReadLine();
}
}
We use a foreach loop so we aren't hard coding the length, which gives flexibility.
Try this instead:
class Program
{
static void Main(string[] args)
{
int x = 0;
string userInput;
Console.WriteLine("Please enter the 10 digit telephone number. ");
userInput = Console.ReadLine();
// Did the user type in more than 10 characters?
if(userInput.Length > 10)
{
// Get the first ten letters, no matter how many letters the user entered
userInput = userInput.Substring(0, 10);
}
// Force values to upper case for comparison
userInput = userInput.ToUpper();
string systemOutput = String.Empty;
foreach(var c in userInput)
{
switch (c)
{
case "1":
systemOutput += "1";
break;
case "A":
case "B":
case "C":
case "2":
systemOutput += "2";
break;
case "D":
case "E":
case "F":
case "3":
systemOutput += "3";
break;
case "G":
case "H":
case "I":
case "4":
systemOutput += "4";
break;
case "J":
case "K":
case "L":
case "5":
systemOutput += "5";
break;
case "M":
case "N":
case "O":
case "6":
systemOutput += "6";
break;
case "P":
case "Q":
case "R":
case "7":
systemOutput += "7";
break;
case "S":
case "T":
case "U":
case "8":
systemOutput += "8";
break;
case "V":
case "W":
case "X":
case "Y":
case "Z":
systemOutput += "9";
break;
case "0":
systemOutput += "0";
break;
}
}
Console.WriteLine(systemOutput);
}
}
You can take benefit of Dictionary for this purpose:
static void Main(string[] args)
{
int x = 0;
string userInput;
Console.WriteLine("Please enter the 10 digit telephone number. ");
userInput = Console.ReadLine();
Dictionary<string,string> dict = new Dictionary<string,string>();
dict.Add("1","1");
dict.Add("ABC2","2");
dict.Add("DEF3","3");
dict.Add("GHI4","4");
dict.Add("JKL5","5");
dict.Add("MNO6","6");
dict.Add("PQR7","7");
dict.Add("STU8","8");
dict.Add("VWXYZ9","9");
dict.Add("0","0");
userInput = string.Join("",userInput.Select(c=>dict.First(k=>k.Key.Contains(c)).Value).ToArray());
Console.WriteLine(userInput);
}
or even more concise:
static void Main(string[] args)
{
int x = 0;
string userInput;
Console.WriteLine("Please enter the 10 digit telephone number. ");
userInput = Console.ReadLine();
string[] s = "0,1,ABC2,DEF3,GHI4,JKL5,MNOP6,PQR7,STU8,VWXYZ9".Split(',');
userInput = string.Join("",userInput.Select(c=>s.Select((x,i)=>new{x,i})
.First(k=>k.x.Contains(c)).i).ToArray());
Console.WriteLine(userInput);
}
I'm really bad at explaining things, but I'll try my best.
I'm making a small program that converts one word into another as you type. Each letter that is typed goes through this section of code where it is changed to a different letter depending on its Index position of the whole word.
My issue here is that when there are repeating letters, the letters that repeat don't change according to their position within the word but rather the first occurrence.
For example this made up word "bacca". If you put that through the code, it SHOULD change to "vrwiy" but instead it changes to "vrwwr". I know why this is too. It's because the switch statement loops through the word that needs to be converted. However I'm without a clue on how to make it change each char according to it's own individual position within the index of the string. I thought maybe the LastIndexOf() method would work but instead it just reverses the order. So if I were to type the letter "a", it would come out as "n", but if I were to type "aa", it would switch the first "a" to "r" because the second is at the IndexOf 1 get's changed to "r".
private void inputTbox_TextChanged(object sender, EventArgs e)
{
List<string> rawZnWordList = new List<string>();
foreach (char a in inputTextBox.Text)
{
switch (inputTextBox.Text.IndexOf(a))
{
case 0:
switch (a)
{
case 'a':
rawZnWordList.Add("n");
continue;
case 'b':
rawZnWordList.Add("v");
continue;
case 'c':
rawZnWordList.Add("a");
continue;
default:
break;
}
continue;
case 1:
switch (a)
{
case 'a':
rawZnWordList.Add("r");
continue;
case 'b':
rawZnWordList.Add("x");
continue;
case 'c':
rawZnWordList.Add("z");
continue;
default:
break;
}
continue;
case 2:
switch (a)
{
case 'a':
rawZnWordList.Add("t");
continue;
case 'b':
rawZnWordList.Add("l");
continue;
case 'c':
rawZnWordList.Add("w");
continue;
default:
continue;
}
continue;
case 3:
switch (a)
{
case 'a':
rawZnWordList.Add("u");
continue;
case 'b':
rawZnWordList.Add("i");
continue;
case 'c':
rawZnWordList.Add("o");
continue;
default:
break;
}
continue;
case 4:
switch (a)
{
case 'a':
rawZnWordList.Add("y");
continue;
case 'b':
rawZnWordList.Add("m");
continue;
case 'c':
rawZnWordList.Add("d");
continue;
default:
break;
}
continue;
default:
break;
}
}
string finalZnWord = string.Join("", rawZnWordList.ToArray());
outputTextBox.Text = finalZnWord;
}
You should try using a for loop instead, like this:
for (int i = 0; i < inputTextBox.Text.Length; i++)
{
char a = inputTextBox.Text[i];
switch (i)
{
case 0:
switch (a)
...
Hope this helps ;).
You need to keep track of the index inside your foreach instead of using .IndexOf. You could also use a regular for loop instead of a foreach but this way is a minimal change to your code.
private void inputTbox_TextChanged(object sender, EventArgs e)
{
List rawZnWordList = new List();
int index = 0;
foreach (char a in inputTextBox.Text)
{
switch (index)
{
case 0:
switch (a)
{
case 'a':
rawZnWordList.Add("n");
continue;
case 'b':
rawZnWordList.Add("v");
continue;
case 'c':
rawZnWordList.Add("a");
continue;
default:
break;
}
continue;
case 1:
switch (a)
{
case 'a':
rawZnWordList.Add("r");
continue;
case 'b':
rawZnWordList.Add("x");
continue;
case 'c':
rawZnWordList.Add("z");
continue;
default:
break;
}
continue;
case 2:
switch (a)
{
case 'a':
rawZnWordList.Add("t");
continue;
case 'b':
rawZnWordList.Add("l");
continue;
case 'c':
rawZnWordList.Add("w");
continue;
default:
continue;
}
continue;
case 3:
switch (a)
{
case 'a':
rawZnWordList.Add("u");
continue;
case 'b':
rawZnWordList.Add("i");
continue;
case 'c':
rawZnWordList.Add("o");
continue;
default:
break;
}
continue;
case 4:
switch (a)
{
case 'a':
rawZnWordList.Add("y");
continue;
case 'b':
rawZnWordList.Add("m");
continue;
case 'c':
rawZnWordList.Add("d");
continue;
default:
break;
}
continue;
default:
break;
}
index++;
}
string finalZnWord = string.Join("", rawZnWordList.ToArray());
outputTextBox.Text = finalZnWord;
}
I think this does the same thing and is a lot more readable. Of course replace the letter rings with your own values. I only went up to 5 characters. I'm guessing you would want more.
//replacement letter rings
char[][] aRep = {
"xfhygaodsekzcpubitlvnjqmrw".ToCharArray(),
"wqtnsepkbalmzyxvordhjgifcu".ToCharArray(),
"nyxgmcibplovkwrszaehftqjud".ToCharArray(),
"soqjhpybuwfxvartkzginemdcl".ToCharArray(),
"pldquhegkaomcnjrfxiysvtbwz".ToCharArray(),
};
private string newText(string inVal)
{
char[] ia = inVal.ToCharArray(); //in array
int l = ia.Length;
char[] oa = new char[l]; //out array
for (int i = 0; i < l; i++)
oa[i] = aRep[i][(int)ia[i]-97]; //lowercase starts at char97
return new string(oa);
}
Here is also the code I used to generate the rings:
//generate random letter rings
//char[] ascii = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
//for (int i = 0; i < 8; i++)
// new string(ascii.OrderBy (x => Guid.NewGuid() ).ToArray()).Dump();
I did some very simple testing and this seemed quite a bit faster than the original approach and more importantly (to me) it is way more readable and a lot easier to see your replacement letter sequences. I think there is some more optimization to be done, but this i think is a good start. Just call this with your text during 'on change'.