For the practice mostly.
This is the code in VB :
Private Function ScrambleWord(ByVal word As String) As String
Dim i As Integer = 0
Dim builder As System.Text.StringBuilder = New System.Text.StringBuilder()
Dim random As Random = New Random()
Dim index As Integer = 0
Dim lower As Integer = 0
Dim upper As Integer = 0
Dim parts() As Char
Dim part As Char
If Not (String.IsNullOrEmpty(word)) Then
If (word.Length > 3) Then
parts = word.ToCharArray()
builder.Append(word.Substring(0, 1))
parts = word.Substring(1, word.Length - 2).ToCharArray()
lower = LBound(parts) : upper = UBound(parts)
For i = lower To upper
index = random.Next(lower, upper)
part = parts(index)
parts(index) = parts(i)
parts(i) = part
Next
builder.Append(parts)
builder.Append(word.Substring(word.Length - 1, 1))
Return builder.ToString()
Else
Return word
End If
Else
Return String.Empty
End If
End Function
I used an online translation site and ended with this:
private string ScrambleWord(string word)
{
int i = 0;
StringBuilder builder = new StringBuilder();
Random random = new Random();
int index = 0;
int lower = 0;
int upper = 0;
char[] parts = null;
char part = '\0';
if (!(string.IsNullOrEmpty(word)))
{
if ((word.Length > 3))
{
parts = word.ToCharArray();
builder.Append(word.Substring(0, 1));
parts = word.Substring(1, word.Length - 2).ToCharArray();
lower = Information.LBound(parts);
upper = Information.UBound(parts);
for (i = lower; i <= upper; i++)
{
index = random.Next(lower, upper);
part = parts[index];
parts[index] = parts[i];
parts[i] = part;
}
builder.Append(parts);
builder.Append(word.Substring(word.Length - 1, 1));
return builder.ToString();
}
else
{
return word;
}
}
else
{
return string.Empty;
}
}
Im not sure if all the translation is good but now im getting two errors since Information not exist in c#
The errors are on the C# code on the lines:
lower = Information.LBound(parts);
upper = Information.UBound(parts);
Both errors are the same:
The name 'Information' does not exist in the current context
I took the VB code from this link and tried to convert it to c#
The Information class
comes from the Microsoft.VisualBasic namespace.
You can add a reference to Microsoft.VisualBasic and add using Microsoft.VisualBasic to the top of your file.
You don't in fact have anything named Information in the current context. (There's nothing declared in the code you posted, either in VB or C#.)
You don't need it anyway. It's being used to access the bounds of the parts array, and you know them already. You used them to create the array in the first place. (And you don't need the VisualBasic namespace.)
parts = word.Substring(1, word.Length - 2).ToCharArray();
lower = 0;
upper = parts.Length; // Note this is one higher than the last index,
// because the first index is zero
for (i = lower; i < upper; i++) // So use < rather than <= here
{
// Other code here.
}
LBounds and UBounds were needed in VB because arrays didn't always have to start at a certain index, as #competent_tech mentions in the comments. It was possible to declare an array with different indexes, even negative ones (eg., Dim parts(-3 To 3)). Also, everything in VB was a variant, so an array could be any type or be multi-dimensional, and the compiler couldn't always tell them apart. (For instance, retrieving cells from Excel in a Range - the result can be one cell, an entire row, or a rectangular or square block of cells.) There's no need for them here, because you know parts is simply a one dimensional character array. Arrays in C# start at index zero, and there's a method to retrieve the length of the array. The last index into the array is one less than that length, as my code above indicates with comments.
Change you code:
instead of
lower = Information.LBound(parts);
upper = Information.UBound(parts);
put
lower = parts.GetLowerBound(0);
upper = parts.GetUpperBound(0);
Information class is specific to VB; when writing C# code
you have to use an equivalent:
Information.LBound(value) == value.GetLowerBound(0);
Information.UBound(value) == value.GetUpperBound(0);
This is what I came up with:
private static string ScrambleWord(string word)
{
// easy exits come first
if (string.IsNullOrEmpty(word))
return String.Empty;
if (word.Length <= 3)
return word;
// now do the work
StringBuilder builder = new StringBuilder();
Random rand = new Random();
builder.Append(word.Substring(0, 1));
List<Char> parts = word.Substring(1).ToList();
while (parts.Count() > 0)
{
int upper = parts.Count();
int index = rand.Next(0, upper);
builder.Append(parts[index]);
parts.RemoveAt(index);
}
return builder.ToString();
}
Someone who is conversant in C# might point out mistakes.
Related
Hi guys, so I need to add a 'space' between each character in my displayed text box.
I am giving the user a masked word like this He__o for him to guess and I want to convert this to H e _ _ o
I am using the following code to randomly replace characters with '_'
char[] partialWord = word.ToCharArray();
int numberOfCharsToHide = word.Length / 2; //divide word length by 2 to get chars to hide
Random randomNumberGenerator = new Random(); //generate rand number
HashSet<int> maskedIndices = new HashSet<int>(); //This is to make sure that I select unique indices to hide. Hashset helps in achieving this
for (int i = 0; i < numberOfCharsToHide; i++) //counter until it reaches words to hide
{
int rIndex = randomNumberGenerator.Next(0, word.Length); //init rindex
while (!maskedIndices.Add(rIndex))
{
rIndex = randomNumberGenerator.Next(0, word.Length); //This is to make sure that I select unique indices to hide. Hashset helps in achieving this
}
partialWord[rIndex] = '_'; //replace with _
}
return new string(partialWord);
I have tried : partialWord[rIndex] = '_ ';however this brings the error "Too many characters in literal"
I have tried : partialWord[rIndex] = "_ "; however this returns the error " Cannot convert type string to char.
Any idea how I can proceed to achieve a space between each character?
Thanks
The following code should do as you ask. I think the code is pretty self explanatory., but feel free to ask if anything is unclear as to the why or how of the code.
// char[] partialWord is used from question code
char[] result = new char[(partialWord.Length * 2) - 1];
for(int i = 0; i < result.Length; i++)
{
result[i] = i % 2 == 0 ? partialWord[i / 2] : ' ';
}
return new string(result);
Since the resulting string is longer than the original string, you can't use only one char array because its length is constant.
Here's a solution with StringBuilder:
var builder = new StringBuilder(word);
for (int i = 0 ; i < word.Length ; i++) {
builder.Insert(i * 2, " ");
}
return builder.ToString().TrimStart(' '); // TrimStart is called here to remove the leading whitespace. If you want to keep it, delete the call.
I am trying to code a simple game where my program randomly selects a word from a dictionary and stores it in a text box/or label? (Not Sure of this part). Then I have another text box where the user enters his guess.
Now I want to give the user some hint.F or example the word:
'game' would look like '_ a m _' or 'g _ _ e'. I have no preference to how the characters are placed.
I have programmed all of the previous code including the random file handling method, all timers and counter etc. I am just stuck on this part.
The program undergoes the following code :
var lines = File.ReadAllLines(#"LOCATION");
textBox3.Text = lines[new Random().Next(lines.Length)];
to select a random word from the file. However the whole word is being shown in textbox 3 and not parts of it like i wish. I am at a complete loss for ideas on how to proceed. I could not find anything similar on the web.
Cheers,
R
Once you pick a random word from file, based on length of the word, decide on how many characters you'd want to hide and then randomly replace those many characters.
something like this-
public string GetPartialWord(string word)
{
if(string.IsNullOrEmpty(word))
{
return string.Empty;
}
char[] partialWord = word.ToCharArray();
int numberOfCharsToHide = word.Length / 2;
Random randomNumberGenerator = new Random();
HashSet<int> maskedIndices = new HashSet<int>();
for(int i=0;i<numberOfCharsToHide;i++)
{
int rIndex = randomNumberGenerator.Next(0, word.Length);
while(!maskedIndices.Add(rIndex))
{
rIndex = randomNumberGenerator.Next(0, word.Length);
}
partialWord[rIndex] = '_';
}
return new string(partialWord);
}
The code below will replace at least half of the characters with underscores. The code takes a word and keeps generating random numbers until it has replaced at least half of the characters with underscores.
public string ConvertToGuessWord(string word)
{
var guessWord = word;
int lastRandom = 0;
do
{
Random rand = new Random();
int thisRandom = 0;
do
{
thisRandom = rand.Next(0, guessWord.Length);
} while (lastRandom == thisRandom);
guessWord = guessWord.Replace(guessWord[thisRandom], '_');
lastRandom = thisRandom;
} while (guessWord.Count(x => x == '_') < (word.Length / 2));
return guessWord;
}
I have a compressed string value I'm extracting from an import file. I need to format this into a parcel number, which is formatted as follows: ##-##-##-###-###. So therefore, the string "410151000640" should become "41-01-51-000-640". I can do this with the following code:
String.Format("{0:##-##-##-###-###}", Convert.ToInt64("410151000640"));
However, The string may not be all numbers; it could have a letter or two in there, and thus the conversion to the int will fail. Is there a way to do this on a string so every character, regardless of if it is a number or letter, will fit into the format correctly?
Regex.Replace("410151000640", #"^(.{2})(.{2})(.{2})(.{3})(.{3})$", "$1-$2-$3-$4-$5");
Or the slightly shorter version
Regex.Replace("410151000640", #"^(..)(..)(..)(...)(...)$", "$1-$2-$3-$4-$5");
I would approach this by having your own formatting method, as long as you know that the "Parcel Number" always conforms to a specific rule.
public static string FormatParcelNumber(string input)
{
if(input.length != 12)
throw new FormatException("Invalid parcel number. Must be 12 characters");
return String.Format("{0}-{1}-{2}-{3}-{4}",
input.Substring(0,2),
input.Substring(2,2),
input.Substring(4,2),
input.Substring(6,3),
input.Substring(9,3));
}
This should work in your case:
string value = "410151000640";
for( int i = 2; i < value.Length; i+=3){
value = value.Insert( i, "-");
}
Now value contains the string with dashes inserted.
EDIT
I just now saw that you didn't have dashes between every second number all the way, to this will require a small tweak (and makes it a bit more clumsy also I'm afraid)
string value = "410151000640";
for( int i = 2; i < value.Length-1; i+=3){
if( value.Count( c => c == '-') >= 3) i++;
value = value.Insert( i, "-");
}
If its part of UI you can use MaskedTextProvider in System.ComponentModel
MaskedTextProvider prov = new MaskedTextProvider("aa-aa-aa-aaa-aaa");
prov.Set("41x151000a40");
string result = prov.ToDisplayString();
Here is a simple extension method with some utility:
public static string WithMask(this string s, string mask)
{
var slen = Math.Min(s.Length, mask.Length);
var charArray = new char[mask.Length];
var sPos = s.Length - 1;
for (var i = mask.Length - 1; i >= 0 && sPos >= 0;)
if (mask[i] == '#') charArray[i--] = s[sPos--];
else
charArray[i] = mask[i--];
return new string(charArray);
}
Use it as follows:
var s = "276000017812008";
var mask = "###-##-##-##-###-###";
var dashedS = s.WithMask(mask);
You can use it with any string and any character other than # in the mask will be inserted. The mask will work from right to left. You can tweak it to go the other way if you want.
Have fun.
If i understodd you correctly youre looking for a function that removes all letters from a string, aren't you?
I have created this on the fly, maybe you can convert it into c# if it's what you're looking for:
Dim str As String = "410151000vb640"
str = String.Format("{0:##-##-##-###-###}", Convert.ToInt64(MakeNumber(str)))
Public Function MakeNumber(ByVal stringInt As String) As String
Dim sb As New System.Text.StringBuilder
For i As Int32 = 0 To stringInt.Length - 1
If Char.IsDigit(stringInt(i)) Then
sb.Append(stringInt(i))
End If
Next
Return sb.ToString
End Function
i have a string like this:
some_string = "A simple demo of SMS text messaging.\r\n+CMGW: 3216\r\n\r\nOK\r\n\"
im coming from vb.net and i need to know in c#, if i know the position of CMGW, how do i get "3216" out of there?
i know that my start should be the position of CMGW + 6, but how do i make it stop as soon as it finds "\r" ??
again, my end result should be 3216
thank you!
Find the index of \r from the start of where you're interested in, and use the Substring overload which takes a length:
// Production code: add validation here.
// (Check for each index being -1, meaning "not found")
int cmgwIndex = text.IndexOf("CMGW: ");
// Just a helper variable; makes the code below slightly prettier
int startIndex = cmgwIndex + 6;
int crIndex = text.IndexOf("\r", startIndex);
string middlePart = text.Substring(startIndex, crIndex - startIndex);
If you know the position of 3216 then you can just do the following
string inner = some_string.SubString(positionOfCmgw+6,4);
This code will take the substring of some_string starting at the given position and only taking 4 characters.
If you want to be more general you could do the following
int start = positionOfCmgw+6;
int endIndex = some_string.IndexOf('\r', start);
int length = endIndex - start;
string inner = some_string.SubString(start, length);
One option would be to start from your known index and read characters until you hit a non-numeric value. Not the most robust solution, but it will work if you know your input's always going to look like this (i.e., no decimal points or other non-numeric characters within the numeric part of the string).
Something like this:
public static int GetNumberAtIndex(this string text, int index)
{
if (index < 0 || index >= text.Length)
throw new ArgumentOutOfRangeException("index");
var sb = new StringBuilder();
for (int i = index; i < text.Length; ++i)
{
char c = text[i];
if (!char.IsDigit(c))
break;
sb.Append(c);
}
if (sb.Length > 0)
return int.Parse(sb.ToString());
else
throw new ArgumentException("Unable to read number at the specified index.");
}
Usage in your case would look like:
string some_string = #"A simple demo of SMS text messaging.\r\n+CMGW: 3216\r\n...";
int index = some_string.IndexOf("CMGW") + 6;
int value = some_string.GetNumberAtIndex(index);
Console.WriteLine(value);
Output:
3216
If you're looking to extract the number portion of 'CMGW: 3216' then a more reliable method would be to use regular expressions. That way you can look for the entire pattern, and not just the header.
var some_string = "A simple demo of SMS text messaging.\r\n+CMGW: 3216\r\n\r\nOK\r\n";
var match = Regex.Match(some_string, #"CMGW\: (?<number>[0-9]+)", RegexOptions.Multiline);
var number = match.Groups["number"].Value;
More general, if you don't know the start position of CMGW but the structure remains as before.
String s;
char[] separators = {'\r'};
var parts = s.Split(separators);
parts.Where(part => part.Contains("CMGW")).Single().Reverse().TakeWhile(c => c != ' ').Reverse();
For example, a user entered "I love this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
the consecutive duplicate exclamation mark "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" should be detected.
The following regular expression would detect repeating chars. You could up the number or limit this to specific characters to make it more robust.
int threshold = 3;
string stringToMatch = "thisstringrepeatsss";
string pattern = "(\\d)\\" + threshold + " + ";
Regex r = new Regex(pattern);
Match m = r.Match(stringToMatch);
while(m.Success)
{
Console.WriteLine("character passes threshold " + m.ToString());
m = m.NextMatch();
}
Here's and example of a function that searches for a sequence of consecutive chars of a specified length and also ignores white space characters:
public static bool HasConsecutiveChars(string source, int sequenceLength)
{
if (string.IsNullOrEmpty(source))
return false;
if (source.Length == 1)
return false;
int charCount = 1;
for (int i = 0; i < source.Length - 1; i++)
{
char c = source[i];
if (Char.IsWhiteSpace(c))
continue;
if (c == source[i+1])
{
charCount++;
if (charCount >= sequenceLength)
return true;
}
else
charCount = 1;
}
return false;
}
Edit fixed range bug :/
Can be done in O(n) easily: for each character, if the previous character is the same as the current, increment a temporary count. If it's different, reset your temporary count. At each step, update your global if needed.
For abbccc you get:
a => temp = 1, global = 1
b => temp = 1, global = 1
b => temp = 2, global = 2
c => temp = 1, global = 2
c => temp = 2, global = 2
c => temp = 3, global = 3
=> c appears three times. Extend it to get the position, then you should be able to print the "ccc" substring.
You can extend this to give you the starting position fairly easily, I'll leave that to you.
Here is a quick solution I crafted with some extra duplicates thrown in for good measure. As others pointed out in the comments, some duplicates are going to be completely legitimate, so you may want to narrow your criteria to punctuation instead of mere characters.
string input = "I loove this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!aa";
int index = -1;
int count =1;
List<string> dupes = new List<string>();
for (int i = 0; i < input.Length-1; i++)
{
if (input[i] == input[i + 1])
{
if (index == -1)
index = i;
count++;
}
else if (index > -1)
{
dupes.Add(input.Substring(index, count));
index = -1;
count = 1;
}
}
if (index > -1)
{
dupes.Add(input.Substring(index, count));
}
The better way i my opinion is create a array, each element in array is responsible for one character pair on string next to each other, eg first aa, bb, cc, dd. This array construct with 0 on each element.
Solve of this problem is a for on this string and update array values.
You can next analyze this array for what you want.
Example: For string: bbaaaccccdab, your result array would be { 2, 1, 3 }, because 'aa' can find 2 times, 'bb' can find one time (at start of string), 'cc' can find three times.
Why 'cc' three times? Because 'cc'cc & c'cc'c & cc'cc'.
Use LINQ! (For everything, not just this)
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index)));
// returns "abb", where each of these items has the previous letter before it
OR
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index))).Any();
// returns true