I have created a scrabble game with a computer opponent. If a blank tile is found in the computer's rack during the word generation if needs to be swapped out for every letter in the alphabet. I have my current solution to solve this problem below, but was wondering if there is a better more efficient way to accomplish this task.
if (str.Contains("*"))
{
char c = 'A';
String made = "";
while(c < 'Z')
{
made = str.ReplaceFirst("*", c.ToString());
if (!made.Contains("*"))
{
wordsMade.Add(made);
if (theGame.theTrie.Search(made) == Trie.SearchResults.Found)
{
validWords.Add(made);
}
}
else
{
char ch = 'A';
String made2 = "";
while (ch < 'Z')
{
made2 = made.ReplaceFirst("*", c.ToString());
wordsMade.Add(made2);
if (theGame.theTrie.Search(made2) == Trie.SearchResults.Found)
{
validWords.Add(made2);
}
ch++;
}
}
c++;
}
Adam is right that the code could be refactored to make it notationally smaller (a lot smaller, in fact), but fundamentally, you have to examine all 26*26 combinations of wildcard characters. So while it is possible to make the code syntactically more efficient, I don't think you can make it algorithmically more efficient.
There's a lot of duplicated code here that can be refactored.
This routine is duplicated, and can be put into a separate method:
wordsMade.Add(made2);
if (theGame.theTrie.Search(made2) == Trie.SearchResults.Found)
{
validWords.Add(made2);
}
To something like this
void addWord(string newWordMade){
wordsMade.Add(newWordMade);
if (theGame.theTrie.Search(newWordMade) == Trie.SearchResults.Found)
{
validWords.Add(newWordMade);
}
}
This loop construct is also duplicated:
char ch = 'A';
String made2 = "";
while (ch < 'Z')
{
made2 = made.ReplaceFirst("*", c.ToString());
wordsMade.Add(made2);
if (theGame.theTrie.Search(made2) == Trie.SearchResults.Found)
{
validWords.Add(made2);
}
ch++;
}
Combining the previous refactor with this one, with a slick lambda, would yield something like this:
void loopCharactersAndDoThis(Action<char> DoThis) {
char ch = 'A';
while (ch < 'Z')
{
DoThis(ch);
ch++;
}
}
else
{
loopCharactersAndDoThis(ch => {
string made2 = made.ReplaceFirst("*", c.ToString());
addWord(made2);
});
}
Or even just:
else
{
loopCharactersAndDoThis(ch => addWord(made.ReplaceFirst("*", c.ToString())));
}
Related
so I have this code. I need to generate a for loop that checks all the characters in the string and checks if they are all valid(So numbers from 0->7). But I don't know how to write it, I tried something but it didn't work. Here are the examples:user enters: 77, code works, user enters 99, code doesn't work, user enters 5., code doesn't work, etc..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NALOGA1
{
class Program
{
static string decToOct(int stevilo)//v mojon primere 7
{
string izhod = "";
//7>0 DRŽI
while (stevilo > 0)
{
//izhodi se dodeli ostanek deljenja z 8 keri se spremeni v string
izhod = (stevilo % 8) + izhod;
//7/8;
stevilo /= 8;
}
return izhod;
}
static int Octtodesetisko(string stevilo)
{
double vsota = 0;
for (int i = stevilo.Length - 1; i >= 0; i--)
{
int stevka = stevilo[i] - '0';
vsota += (stevka * Math.Pow(8, i));
}
return (int)vsota;
}
static void Main(string[] args)
{
//3 podprogram-in progress
string prvastevilka = Console.ReadLine();
int prvasprememba = Int32.Parse(prvastevilka);
if (prvasprememba > 0)
{
Console.WriteLine(decToOct(prvasprememba));
}
else
{
Console.WriteLine("Napaka");
}
string drugastevilka = Console.ReadLine();
int drugasprememba = Octtodesetisko(drugastevilka);
foreach (char znak in drugastevilka)
{
if(znak!=1 || znak!=2 || znak!=3 || znak!=4 || znak!=5 || znak!=6 || znak!=7)
{
Console.WriteLine("Napaka");
}
else
{
Console.WriteLine("dela :D");
}
}
Console.ReadKey();
}
}
}
Personally, I would take advantage of the LINQ Enumerable.All method to express this in a very concise and readable way:
if (str.Any() && str.All(c => c >= '0' && c <= '7'))
{
Console.WriteLine("good");
}
else
{
Console.WriteLine("bad");
}
EDIT: No LINQ
It's not hard to translate what the LINQ Enumerable.All method does to a normal loop. It's just more verbose:
bool isValid = true;
foreach (char c in str)
{
if (c < '0' || c > '7')
{
isValid = false;
break;
}
}
if (str.Length != 0 && isValid)
{
Console.WriteLine("good");
}
else
{
Console.WriteLine("bad");
}
Firstly, there seems to be a mistake in the line
if(znak!=1 || znak!=2 || znak!=3 || znak!=4 || znak!=5 || znak!=6 || znak!=7)
I guess it should read
if(znak!='1' || znak!='2' || znak!='3' || znak!='4' || znak!='5' || znak!='6' || znak!='7')
which should be compressed to
if (znak >= '0' && znak <= '7')
You can use linq instead of the for loop here like this:
if (drugastevilka.All(c => c >= '0' && c <= '7')
Console.WriteLine("dela :D");
else
Console.WriteLine("Napaka");
But the best solution is probably to use a regular expression:
Regex regex = new Regex("^[0-7]+$");
if (regex.IsMatch(drugastevilka))
Console.WriteLine("dela :D");
else
Console.WriteLine("Napaka");
Edit: the linq solution shown accepts empty strings, the regex (as shown) needs at least 1 character. Exchange the + with a * and it will accept empty strings, too. But I don't think you want to accept empty strings.
You are messing up with the datatype
Can you try with below code
static string decToOct(int stevilo)//v mojon primere 7
{
int izhod = 0;
//7>0 DRŽI
while (stevilo > 0)
{
//izhodi se dodeli ostanek deljenja z 8 keri se spremeni v string
izhod = (stevilo % 8) + izhod;
//7/8;
stevilo /= 8;
}
return (izhod.ToString());
}
What about something like this?
class Program
{
static void Main(string[] args)
{
string someString = "1234567";
string someOtherString = "1287631";
string anotherString = "123A6F2";
Console.WriteLine(IsValidString(someString));
Console.WriteLine(IsValidString(someOtherString));
Console.WriteLine(IsValidString(anotherString));
Console.ReadLine();
}
public static bool IsValidString(string str)
{
bool isValid = true;
char[] splitString = str.ToCharArray(); //get an array of each character
for (int i = 0; i < splitString.Length; i++)
{
try
{
double number = Char.GetNumericValue(splitString[i]); //try to convert the character to a double (GetNumericValue returns a double)
if (number < 0 || number > 7) //we get here if the character is an int, then we check for 0-7
{
isValid = false; //if the character is invalid, we're done.
break;
}
}
catch (Exception) //this will hit if we try to convert a non-integer character.
{
isValid = false;
break;
}
}
return isValid;
}
}
IsValidString() takes a string, converts it to a Char array, then checks each value as such:
Get the numeric value
Check if the value is between 0-7
GetNumericValue will fail on a non-integer character, so we wrap it in a try/catch - if we hit an exception we know that isValid = false, so we break.
If we get a valid number, and it's not between 0-7 we also know that isValid = false, so we break.
If we make it all the way through the list, the string is valid.
The sample given above returns:
IsValidString(someString) == true
IsValidString(someOtherString) == false
IsValidString(anotherString) == false
since my prof won't let me use RegEx, I'm stuck with using loops to check each character on a string.
Does anyone have a sample code/algorithm?
public void setAddress(string strAddress)
{
do
{
foreach (char c in Name)
{
if ( /*check for characters*/ == false)
{
Address = strAddress;
}
}
if ( /*check for characters*/ == true)
{
Console.Write("Invalid!");
}
} while ( /*check for characters*/ == true)
}
public int getAddress()
{
return Address;
}
I need to only include letters and numbers. Characters such as !##$%^& are not allowed.
I'm not allowed to use RegEx because he hasn't taught that to us yet... well I couldn't attend class on the day he taught these loops and character checking, so now he won't tell me more. ANYWAY, if there's a more efficient way without using RegEx, that'd be helpful.
string s = #"$KUH% I*$)OFNlkfn$";
var withoutSpecial = new string(s.Where(c => Char.IsLetterOrDigit(c)
|| Char.IsWhiteSpace(c)).ToArray());
if (s != withoutSpecial)
{
Console.WriteLine("String contains special chars");
}
You can do it without loops at all :)
Source: https://stackoverflow.com/a/4503614/1714342
EDIT:
if(s.Any(c=>c => !Char.IsLetterOrDigit(c) || !Char.IsWhiteSpace(c))
{
Console.WriteLine("String contains special chars");
}
You may not need loops at all, just character checking will do:
if (Name.IndexofAny("!##$%^&*()".ToCharArray() != -1))
Console.WriteLine("Valid Address");
else
Console.WriteLine("Invalid Address");
See http://msdn.microsoft.com/en-us/library/system.string.indexofany.aspx
A solution with explicit loop could be
String s = #"$KUH% I*$)OFNlkfn$";
foreach (Char c in s)
if (!(Char.IsLetterOrDigit(c) || Char.IsWhiteSpace(c))) {
Console.WriteLine("String contains special chars");
break;
}
bool check_for_characters(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
I was using WebUtilty.HtmlDecode to decode HTML. It turns out that it doesn't decode properly, for example, – is supposed to decode to a "–" character, but WebUtilty.HtmlDecode does not decode it. HttpUtilty.HtmlDecode, however, does.
Debug.WriteLine(WebUtility.HtmlDecode("–"));
Debug.WriteLine(HttpUtility.HtmlDecode("–"));
> –
> –
The documentation for both of these is the same:
Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.
Why are they different, which one should I be using, and what will change if I switch to WebUtility.HtmlDecode to get "–" to decode correctly?
The implementation of the two methods are indeed different on Windows Phone.
WebUtility.HtmlDecode:
public static void HtmlDecode(string value, TextWriter output)
{
if (value != null)
{
if (output == null)
{
throw new ArgumentNullException("output");
}
if (!StringRequiresHtmlDecoding(value))
{
output.Write(value);
}
else
{
int length = value.Length;
for (int i = 0; i < length; i++)
{
bool flag;
uint num4;
char ch = value[i];
if (ch != '&')
{
goto Label_01B6;
}
int num3 = value.IndexOfAny(_htmlEntityEndingChars, i + 1);
if ((num3 <= 0) || (value[num3] != ';'))
{
goto Label_01B6;
}
string entity = value.Substring(i + 1, (num3 - i) - 1);
if ((entity.Length <= 1) || (entity[0] != '#'))
{
goto Label_0188;
}
if ((entity[1] == 'x') || (entity[1] == 'X'))
{
flag = uint.TryParse(entity.Substring(2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out num4);
}
else
{
flag = uint.TryParse(entity.Substring(1), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num4);
}
if (flag)
{
switch (_htmlDecodeConformance)
{
case UnicodeDecodingConformance.Strict:
flag = (num4 < 0xd800) || ((0xdfff < num4) && (num4 <= 0x10ffff));
goto Label_0151;
case UnicodeDecodingConformance.Compat:
flag = (0 < num4) && (num4 <= 0xffff);
goto Label_0151;
case UnicodeDecodingConformance.Loose:
flag = num4 <= 0x10ffff;
goto Label_0151;
}
flag = false;
}
Label_0151:
if (!flag)
{
goto Label_01B6;
}
if (num4 <= 0xffff)
{
output.Write((char) num4);
}
else
{
char ch2;
char ch3;
ConvertSmpToUtf16(num4, out ch2, out ch3);
output.Write(ch2);
output.Write(ch3);
}
i = num3;
goto Label_01BD;
Label_0188:
i = num3;
char ch4 = HtmlEntities.Lookup(entity);
if (ch4 != '\0')
{
ch = ch4;
}
else
{
output.Write('&');
output.Write(entity);
output.Write(';');
goto Label_01BD;
}
Label_01B6:
output.Write(ch);
Label_01BD:;
}
}
}
}
HttpUtility.HtmlDecode:
public static string HtmlDecode(string html)
{
if (html == null)
{
return null;
}
if (html.IndexOf('&') < 0)
{
return html;
}
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb, CultureInfo.InvariantCulture);
int length = html.Length;
for (int i = 0; i < length; i++)
{
char ch = html[i];
if (ch == '&')
{
int num3 = html.IndexOfAny(s_entityEndingChars, i + 1);
if ((num3 > 0) && (html[num3] == ';'))
{
string entity = html.Substring(i + 1, (num3 - i) - 1);
if ((entity.Length > 1) && (entity[0] == '#'))
{
try
{
if ((entity[1] == 'x') || (entity[1] == 'X'))
{
ch = (char) int.Parse(entity.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
}
else
{
ch = (char) int.Parse(entity.Substring(1), CultureInfo.InvariantCulture);
}
i = num3;
}
catch (FormatException)
{
i++;
}
catch (ArgumentException)
{
i++;
}
}
else
{
i = num3;
char ch2 = HtmlEntities.Lookup(entity);
if (ch2 != '\0')
{
ch = ch2;
}
else
{
writer.Write('&');
writer.Write(entity);
writer.Write(';');
continue;
}
}
}
}
writer.Write(ch);
}
return sb.ToString();
}
Interestingly, WebUtility doesn't exist on WP7. Also, the WP8 implementation of WebUtility is identical to the desktop one. The desktop implementation of HttpUtility.HtmlDecode is just a wrapper around WebUtility.HtmlDecode. Last but not least, Silverlight 5 has the same implementation of HttpUtility.HtmlDecode as Windows Phone, and does not implement WebUtility.
From there, I can venture a guess: since the Windows Phone 7 runtime is based on Silverlight, WP7 inherited of the Silverlight version of HttpUtility.HtmlDecode, and WebUtility wasn't present. Then came WP8, whose runtime is based on WinRT. WinRT brought WebUtility, and the old version of HttpUtility.HtmlDecode was kept to ensure the compatibility with the legacy WP7 apps.
As to know which one you should use... If you want to target WP7 then you have no choice but to use HttpUtility.HtmlDecode. If you're targeting WP8, then just pick the method whose behavior suits your needs the best. WebUtility is probably the future-proof choice, just in case Microsoft decides to ditch the Silverlight runtime in an upcoming version of Windows Phone. But I'd just go with the practical choice of picking HttpUtility to not have to worry about manually supporting the example you've put in your question.
The methods do exactly the same. Moreover if you try to decompile them the implementations look like one was just copied from another.
The difference is only intended use. HttpUtility is contained in the System.Web assembly and is expected to be used in ASP.net applications which are built over this assembly. WebUtility is contained in the System assembly referenced by nearly all applications and is provided for more general purpose or client use.
Just to notify others who will find this in search. Use any function that mentioned in the question, but never use Windows.Data.Html.HtmlUtilities.ConvertToText(string input). It's 70 times slower than WebUtilty.HtmlDecode and produce crashes! Crash will be named as mshtml!IEPeekMessage in the DevCenter. It looks like this function call InternetExplorer to convert the string. Just avoid it.
I am working on a logic that decreases the value of an alphanumeric List<char>. For example, A10 becomes A9, BBA becomes BAZ, 123 becomes 122. And yes, if the value entered is the last one(like A or 0), then I should return -
An additional overhead is that there is a List<char> variable which is maintained by the user. It has characters which are to be skipped. For example, if the list contains A in it, the value GHB should become GGZ and not GHA.
The base of this logic is a very simple usage of decreasing the char but with these conditions, I am finding it very difficult.
My project is in Silverlight, the language is C#. Following is my code that I have been trying to do in the 3 methods:
List<char> lstGetDecrName(List<char> lstVal)//entry point of the value that returns decreased value
{
List<char> lstTmp = lstVal;
subCheckEmpty(ref lstTmp);
switch (lstTmp.Count)
{
case 0:
lstTmp.Add('-');
return lstTmp;
case 1:
if (lstTmp[0] == '-')
{
return lstTmp;
}
break;
case 2:
if (lstTmp[1] == '0')
{
if (lstTmp[0] == '1')
{
lstTmp.Clear();
lstTmp.Add('9');
return lstTmp;
}
if (lstTmp[0] == 'A')
{
lstTmp.Clear();
lstTmp.Add('-');
return lstTmp;
}
}
if (lstTmp[1] == 'A')
{
if (lstTmp[0] == 'A')
{
lstTmp.Clear();
lstTmp.Add('Z');
return lstTmp;
}
}
break;
}
return lstGetDecrValue(lstTmp,lstVal);
}
List<char> lstGetDecrValue(List<char> lstTmp,List<char> lstVal)
{
List<char> lstValue = new List<char>();
switch (lstTmp.Last())
{
case 'A':
lstValue = lstGetDecrTemp('Z', lstTmp, lstVal);
break;
case 'a':
lstValue = lstGetDecrTemp('z', lstTmp, lstVal);
break;
case '0':
lstValue = lstGetDecrTemp('9', lstTmp, lstVal);
break;
default:
char tmp = (char)(lstTmp.Last() - 1);
lstTmp.RemoveAt(lstTmp.Count - 1);
lstTmp.Add(tmp);
lstValue = lstTmp;
break;
}
return lstValue;
}
List<char> lstGetDecrTemp(char chrTemp, List<char> lstTmp, List<char> lstVal)//shifting places eg unit to ten,etc.
{
if (lstTmp.Count == 1)
{
lstTmp.Clear();
lstTmp.Add('-');
return lstTmp;
}
lstTmp.RemoveAt(lstTmp.Count - 1);
lstVal = lstGetDecrName(lstTmp);
lstVal.Insert(lstVal.Count, chrTemp);
return lstVal;
}
I seriously need help for this. Please help me out crack through this.
The problem you are trying to solve is actually how to decrement discreet sections of a sequence of characters, each with it's own counting system, where each section is separated by a change between Alpha and Numeric. The rest of the problem is easy once you identify this.
The skipping of unwanted characters is simply a matter of repeating the decrement if you get an unwanted character in the result.
One difficultly is the ambiguous definition of the sequences. e.g. what to do when you get down to say A00, what is next? "A" or "-". For the sake of argument I am assuming a practical implementation based loosely on Excel cell names (i.e. each section operates independently of the others).
The code below does 95% of what you wanted, however there is a bug in the exclusions code. e.g. "ABB" becomes "AAY". I feel the exclusions need to be applied at a higher level (e.g. repeat decrement until no character is in the exclusions list), but I don't have time to finish it now. Also it is resulting in a blank string when it counts down to nothing, rather than the "-" you wanted, but that is trivial to add at the end of the process.
Part 1 (divide the problem into sections):
public static string DecreaseName( string name, string exclusions )
{
if (string.IsNullOrEmpty(name))
{
return name;
}
// Split the problem into sections (reverse order)
List<StringBuilder> sections = new List<StringBuilder>();
StringBuilder result = new StringBuilder(name.Length);
bool isNumeric = char.IsNumber(name[0]);
StringBuilder sb = new StringBuilder();
sections.Add(sb);
foreach (char c in name)
{
// If we change between alpha and number, start new string.
if (char.IsNumber(c) != isNumeric)
{
isNumeric = char.IsNumber(c);
sb = new StringBuilder();
sections.Insert(0, sb);
}
sb.Append(c);
}
// Now process each section
bool cascadeToNext = true;
foreach (StringBuilder section in sections)
{
if (cascadeToNext)
{
result.Insert(0, DecrementString(section, exclusions, out cascadeToNext));
}
else
{
result.Insert(0, section);
}
}
return result.ToString().Replace(" ", "");
}
Part2 (decrement a given string):
private static string DecrementString(StringBuilder section, string exclusions, out bool cascadeToNext)
{
bool exclusionsExist = false;
do
{
exclusionsExist = false;
cascadeToNext = true;
// Process characters in reverse
for (int i = section.Length - 1; i >= 0 && cascadeToNext; i--)
{
char c = section[i];
switch (c)
{
case 'A':
c = (i > 0) ? 'Z' : ' ';
cascadeToNext = (i > 0);
break;
case 'a':
c = (i > 0) ? 'z' : ' ';
cascadeToNext = (i > 0);
break;
case '0':
c = (i > 0) ? '9' : ' ';
cascadeToNext = (i > 0);
break;
case ' ':
cascadeToNext = false;
break;
default:
c = (char)(((int)c) - 1);
if (i == 0 && c == '0')
{
c = ' ';
}
cascadeToNext = false;
break;
}
section[i] = c;
if (exclusions.Contains(c.ToString()))
{
exclusionsExist = true;
}
}
} while (exclusionsExist);
return section.ToString();
}
The dividing can of course be done more efficiently, just passing start and end indexes to the DecrementString, but this is easier to write & follow and not much slower in practical terms.
do a check if its a number if so then do a minus math of the number, if its a string then change it to char codes and then the char code minus 1
I couldn't stop thinking about this yesterday, so here's an idea. Note, this is just pseudo-code, and not tested, but I think the idea is valid and should work (with a few modifications).
The main point is to define your "alphabet" directly, and specify which characters in it are illegal and should be skipped, then use a list or array of positions in this alphabet to define the word you start with.
I can't spend any more time on this right now, but please let me know if you decide to use it and get it to work!
string[] alphabet = {a, b, c, d, e};
string[] illegal = {c, d};
public string ReduceString(string s){
// Create a list of the alphabet-positions for each letter:
int[] positionList = s.getCharsAsPosNrsInAlphabet();
int[] reducedPositionList = ReduceChar(positionList, positionList.length);
string result = "";
foreach(int pos in reducedPositionList){
result += alphabet[pos];
}
return result;
}
public string ReduceChar(string[] positionList, posToReduce){
int reducedCharPosition = ReduceToNextLegalChar(positionList[posToReduce]);
// put reduced char back in place:
positionList[posToReduce] = reducedCharPosition;
if(reducedCharPosition < 0){
if(posToReduce <= 0){
// Reached the end, reduced everything, return empty array!:
return new string[]();
}
// move to back of alphabet again (ie, like the 9 in "11 - 2 = 09"):
reducedCharPosition += alphabet.length;
// Recur and reduce next position (ie, like the 0 in "11 - 2 = 09"):
return ReduceChar(positionList, posToReduce-1);
}
return positionList;
}
public int ReduceToNextLegalChar(int pos){
int nextPos = pos--;
return (isLegalChar(nextPos) ? nextPos : ReduceToNextLegalChar(nextPos));
}
public boolean IsLegalChar(int pos){
return (! illegal.contains(alphabet[pos]));
}
enter code here
Without writing all your code for you, here's a suggestion as to how you can break this down:
char DecrementAlphaNumericChar(char input, out bool hadToWrap)
{
if (input == 'A')
{
hadToWrap = true;
return 'Z';
}
else if (input == '0')
{
hadToWrap = true;
return '9';
}
else if ((input > 'A' && input <= 'Z') || (input > '0' && input <= '9'))
{
hadToWrap = false;
return (char)((int)input - 1);
}
throw new ArgumentException(
"Characters must be digits or capital letters",
"input");
}
char DecrementAvoidingProhibited(
char input, List<char> prohibited, out bool hadToWrap)
{
var potential = DecrementAlphaNumericChar(input, out hadToWrap);
while (prohibited.Contains(potential))
{
bool temp;
potential = DecrementAlphaNumericChar(potential, out temp);
if (potential == input)
{
throw new ArgumentException(
"A whole class of characters was prohibited",
"prohibited");
}
hadToWrap |= temp;
}
return potential;
}
string DecrementString(string input, List<char> prohibited)
{
char[] chrs = input.ToCharArray();
for (int i = chrs.Length - 1; i >= 0; i--)
{
bool wrapped;
chrs[i] = DecrementAvoidingProhibited(
chrs[i], prohibited, out wrapped);
if (!wrapped)
return new string(chrs);
}
return "-";
}
The only issue here is that it will reduce e.g. A10 to A09 not A9. I actually prefer this myself, but it should be simple to write a final pass that removes the extra zeroes.
For a little more performance, replace the List<char>s with Hashset<char>s, they should allow a faster Contains lookup.
I found solution to my own answer with some other workarounds.
The calling function:
MyFunction()
{
//stuff I do before
strValue = lstGetDecrName(strValue.ToList());//decrease value here
if (strValue.Contains('-'))
{
strValue = "-";
}
//stuff I do after
}
In all there are 4 functions. 2 Main functions and 2 helper functions.
List<char> lstGetDecrName(List<char> lstVal)//entry point, returns decreased value
{
if (lstVal.Contains('-'))
{
return "-".ToList();
}
List<char> lstTmp = lstVal;
subCheckEmpty(ref lstTmp);
switch (lstTmp.Count)
{
case 0:
lstTmp.Add('-');
return lstTmp;
case 1:
if (lstTmp[0] == '-')
{
return lstTmp;
}
break;
case 2:
if (lstTmp[1] == '0')
{
if (lstTmp[0] == '1')
{
lstTmp.Clear();
lstTmp.Add('9');
return lstTmp;
}
if (lstTmp[0] == 'A')
{
lstTmp.Clear();
lstTmp.Add('-');
return lstTmp;
}
}
if (lstTmp[1] == 'A')
{
if (lstTmp[0] == 'A')
{
lstTmp.Clear();
lstTmp.Add('Z');
return lstTmp;
}
}
break;
}
List<char> lstValue = new List<char>();
switch (lstTmp.Last())
{
case 'A':
lstValue = lstGetDecrTemp('Z', lstTmp, lstVal);
break;
case 'a':
lstValue = lstGetDecrTemp('z', lstTmp, lstVal);
break;
case '0':
lstValue = lstGetDecrTemp('9', lstTmp, lstVal);
break;
default:
char tmp = (char)(lstTmp.Last() - 1);
lstTmp.RemoveAt(lstTmp.Count - 1);
lstTmp.Add(tmp);
subCheckEmpty(ref lstTmp);
lstValue = lstTmp;
break;
}
lstGetDecrSkipValue(lstValue);
return lstValue;
}
List<char> lstGetDecrSkipValue(List<char> lstValue)
{
bool blnSkip = false;
foreach (char tmpChar in lstValue)
{
if (lstChars.Contains(tmpChar))
{
blnSkip = true;
break;
}
}
if (blnSkip)
{
lstValue = lstGetDecrName(lstValue);
}
return lstValue;
}
void subCheckEmpty(ref List<char> lstTmp)
{
bool blnFirst = true;
int i = -1;
foreach (char tmpChar in lstTmp)
{
if (char.IsDigit(tmpChar) && blnFirst)
{
i = tmpChar == '0' ? lstTmp.IndexOf(tmpChar) : -1;
if (tmpChar == '0')
{
i = lstTmp.IndexOf(tmpChar);
}
blnFirst = false;
}
}
if (!blnFirst && i != -1)
{
lstTmp.RemoveAt(i);
subCheckEmpty(ref lstTmp);
}
}
List<char> lstGetDecrTemp(char chrTemp, List<char> lstTmp, List<char> lstVal)//shifting places eg unit to ten,etc.
{
if (lstTmp.Count == 1)
{
lstTmp.Clear();
lstTmp.Add('-');
return lstTmp;
}
lstTmp.RemoveAt(lstTmp.Count - 1);
lstVal = lstGetDecrName(lstTmp);
lstVal.Insert(lstVal.Count, chrTemp);
subCheckEmpty(ref lstVal);
return lstVal;
}
I have raw binary data received from device. I would like to display that data something like HEX editors do - display hex values, but also display corresponding characters.
I found fonts that have characters for ASCII codes 0 - 32, but I cannot get them to show on screen.
I tried this with WPF listbox, itemscontrol and textbox.
Is there some setting that can make this work?
Or maybe some WPF control that will show this characters?
Edit:
After some thinking and testing, only characters that make problems are line feed, form feed, carriage return, backspace, horizontal and vertical tab. As quick solution I decided to replace those characters with ASCII 16 (10HEX) character. I tested this with ASCII, UTF-8 and Unicode files and it works with those three formats.
Here is regex that I am using for this:
rawLine = Regex.Replace(inputLine, "[\t\n\r\f\b\v]", '\x0010'.ToString());
It replaces all occurrences of this 6 problematic characters with some boxy sign. It shows that this is not "regular printable" character and it works for me.
Not sure if that's excatly what you want, but I would recommend you to have a look in the #develop project. Their editor can display spaces, tabs and end-of-line markers.
I had a quick look at the source code and in the namespace ICSharpCode.AvalonEdit.Rendering the SingleCharacterElementGenerator class, seems to do what you want.
This should help you can expand it
private static string GetPrintableCharacter(char character)
{
switch (character)
{
case '\a':
{
return "\\a";
}
case '\b':
{
return "\\b";
}
case '\t':
{
return "\\t";
}
case '\n':
{
return "\\n";
}
case '\v':
{
return "\\v";
}
case '\f':
{
return "\\f";
}
case '\r':
{
return "\\r";
}
default:
{
if (character == ' ')
{
break;
}
else
{
throw new InvalidArgumentException(Resources.NOTSUPPORTCHAR, new object[] { character });
}
}
}
return "\\x20";
}
public static string GetPrintableText(string text)
{
StringBuilder stringBuilder = new StringBuilder(1024);
if (text == null)
{
return "[~NULL~]";
}
if (text.Length == 0)
{
return "[~EMPTY~]";
}
stringBuilder.Remove(0, stringBuilder.Length);
int num = 0;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\a' || text[i] == '\b' || text[i] == '\f' || text[i] == '\v' || text[i] == '\t' || text[i] == '\n' || text[i] == '\r' || text[i] == ' ')
{
num += 3;
}
}
int length = text.Length + num;
if (stringBuilder.Capacity < length)
{
stringBuilder = new StringBuilder(length);
}
string str = text;
for (int j = 0; j < str.Length; j++)
{
char chr = str[j];
if (chr > ' ')
{
stringBuilder.Append(chr);
}
else
{
stringBuilder.Append(StringHelper.GetPrintableCharacter(chr));
}
}
return stringBuilder.ToString();
}