how to Tryparse Numbers from Text file like ascii art with c#? - c#

how can i get the numbers that are coded in a ascii art with sticks?
the numberss are in a txt file und it contains this:
I must get the nubmers that are drown with stick.
the first step is to get 4 line and than to controll it with an Alphabet.
i get the text in a string[]
string[] lines = File.ReadAllLines("SourceFile.txt");
the first 4 line are up to lines[3].
how can i controll the different line in the same position?
it is like a 2d Array or i must do something else?

First of all you need an object that stores the pattern and metrics of a symbol(number in your case). Also this object has a method for recognizing its pattern in the given array:
public class AsciiNumber
{
private readonly char[][] _data;
public AsciiNumber(char character, char[][] data)
{
this._data = data;
this.Character = character;
}
public char Character
{
get;
private set;
}
public int Width
{
get
{
return this._data[0].Length;
}
}
public int Height
{
get
{
return this._data.Length;
}
}
public bool Match(string[] source, int startRow, int startColumn)
{
if (startRow + this.Height > source.Length)
{
return false;
}
for (var i = startRow; i < startRow + this.Height; i++)
{
var row = source[i];
if (startColumn + this.Width > row.Length)
{
return false;
}
for (var j = startColumn; j < startColumn + this.Width; j++)
{
if (this._data[i - startRow][j - startColumn] != row[j])
{
return false;
}
}
}
return true;
}
}
Then you may create something like alphabet you deal with (I used only numbers 1 and 3):
public static class Alphabet
{
private static readonly AsciiNumber Number1 = new AsciiNumber('1', new[]{
new []{'|'},
new []{'|'},
new []{'|'},
new []{'|'},
});
private static readonly AsciiNumber Number3 = new AsciiNumber('3', new[]{
new []{'-','-','-'},
new []{' ',' ','/'},
new []{' ',' ','\\'},
new []{'-','-','-'},
});
public static readonly IEnumerable<AsciiNumber> All = new[] { Number1, Number3 };
}
Assuming that numbers in your source file have permament and equal height you may try code like this:
string[] lines = File.ReadAllLines("SourceFile.txt");
var lineHeight = 4;
var text = new StringBuilder();
for (var i = 0; i < lines.Length; i += lineHeight)
{
var j = 0;
while (j < lines[i].Length)
{
var match = Alphabet.All.FirstOrDefault(character => character.Match(lines, i, j));
if (match != null)
{
text.Append(match.Character);
j += match.Width;
}
else
{
j++;
}
}
}
Console.WriteLine("Recognized numbers: {0}", text.ToString());
N.B. If line height changes over the file you have to improve the code above.

Let's suppose we have this text and we want to parse the numbers in it:
--- --- | | | -----
/ _| | |__| |___
\ | | | |
-- --- | | ____|
First of all, we should remove any unnecessary white-space (or tab, if present) and put a separator char (e.g. $) between the numbers, obtaining something similar to this:
$---$---$|$| |$-----$
$ / $ _|$|$|__|$|___ $
$ \ $| $|$ |$ |$
$-- $---$|$ |$____|$
Now we should call the Split function on each line of the text, using $ as separator, and then compare the results with an alphabet.
Let's see how to do this with code. Given the text to parse string[] lines, we'll create an extension method to remove unnecessary white-spaces and put a separator char/string instead:
public static class StringHelperClass
{
// Extension method to remove any unnecessary white-space and put a separator char instead.
public static string[] ReplaceSpacesWithSeparator(this string[] text, string separator)
{
// Create an array of StringBuilder, one for every line in the text.
StringBuilder[] stringBuilders = new StringBuilder[text.Length];
// Initialize stringBuilders.
for (int n = 0; n < text.Length; n++)
stringBuilders[n] = new StringBuilder().Append(separator);
// Get shortest line in the text, in order to avoid Out Of Range Exception.
int shorterstLine = text.Min(line => line.Length);
// Temporary variables.
int lastSeparatorIndex = 0;
bool previousCharWasSpace = false;
// Start processing the text, char after char.
for (int n = 0; n < shorterstLine; ++n)
{
// Look for white-spaces on the same position on
// all the lines of the text.
if (text.All(line => line[n] == ' '))
{
// Go to next char if previous char was also a white-space,
// or if this is the first white-space char of the text.
if (previousCharWasSpace || n == 0)
{
previousCharWasSpace = true;
lastSeparatorIndex = n + 1;
continue;
}
previousCharWasSpace = true;
// Append non white-space chars to the StringBuilder
// of each line, for later use.
for (int i = lastSeparatorIndex; i < n; ++i)
{
for (int j = 0; j < text.Length; j++)
stringBuilders[j].Append(text[j][i]);
}
// Append separator char.
for (int j = 0; j < text.Length; j++)
stringBuilders[j].Append(separator);
lastSeparatorIndex = n + 1;
}
else
previousCharWasSpace = false;
}
for (int j = 0; j < text.Length; j++)
text[j] = stringBuilders[j].ToString();
// Return formatted text.
return text;
}
}
Then, in the Main method, we'll use:
lines = lines.ReplaceSpacesWithSeparator("$");
and
ASCIINumbersParser parser = new ASCIINumbersParser(lines, "$");
where ASCIINumbersParser is this class:
public class ASCIINumbersParser
{
// Will store a list of all the possible numbers
// found in the text.
public List<string[]> CandidatesList { get; }
public ASCIINumbersParser(string[] text, string separator)
{
CandidatesList = new List<string[]>();
string[][] candidates = new string[text.Length][];
for (int n = 0; n < text.Length; ++n)
{
// Split each line in the text, using the separator char/string.
candidates[n] =
text[n].Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
}
// Put the strings in such a way that each CandidateList item
// contains only one possible number found in the text.
for (int i = 0; i < candidates[0].Length; ++i)
CandidatesList.Add(candidates.Select(c => c[i]).ToArray());
}
}
At this point, we will use the following class to generate an ASCII art representation of some numbers and to compare the result with our original string (in Main):
public static class ASCIINumberHelper
{
// Get an ASCII art representation of a number.
public static string[] GetASCIIRepresentationForNumber(int number)
{
switch (number)
{
case 1:
return new[]
{
"|",
"|",
"|",
"|"
};
case 2:
return new[]
{
"---",
" _|",
"| ",
"---"
};
case 3:
return new[]
{
"---",
" / ",
#" \ ",
"-- "
};
case 4:
return new[]
{
"| |",
"|__|",
" |",
" |"
};
case 5:
return new[]
{
"-----",
"|___ ",
" |",
"____|"
};
default:
return null;
}
}
// See if two numbers represented as ASCII art are equal.
public static bool ASCIIRepresentationMatch(string[] number1, string[] number2)
{
// Return false if the any of the two numbers is null
// or their lenght is different.
// if (number1 == null || number2 == null)
// return false;
// if (number1.Length != number2.Length)
// return false;
if (number1?.Length != number2?.Length)
return false;
try
{
for (int n = 0; n < number1.Length; ++n)
{
if (number1[n].CompareTo(number2[n]) != 0)
return false;
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex);
return false;
}
return true;
}
}
In the end, the Main function will look like this:
static void Main()
{
string ASCIIString = #"
--- --- | | | -----
/ _| | |__| |___
\ | | | |
-- --- | | ____| ";
string[] lines =
ASCIIString.Split(new[] {"\n","\r\n"}, StringSplitOptions.RemoveEmptyEntries);
lines = lines.ReplaceSpacesWithSeparator("$");
ASCIINumbersParser parser = new ASCIINumbersParser(lines, "$");
// Try to find all numbers contained in the ASCII string
foreach (string[] candidate in parser.CandidatesList)
{
for (int i = 1; i < 10; ++i)
{
string[] num = ASCIINumberHelper.GetASCIIRepresentationForNumber(i);
if (ASCIINumberHelper.ASCIIRepresentationMatch(num, candidate))
Console.WriteLine("Number {0} was found in the string.", i);
}
}
}
// Expected output:
// Number 3 was found in the string.
// Number 2 was found in the string.
// Number 1 was found in the string.
// Number 4 was found in the string.
// Number 5 was found in the string.
Here you can find the full code.

I created all the models and saved them in the Dictionary.
I will create the directories for development
C:\temp\Validate C:\temp\Referenz C:\temp\Extract
In Dir Reference, a file will be created for each Model in the Dictionary.
I read all the lines, and save them in a string [].
Encoding I will do it personally from string [] to char [] []. After this operation we will have in Dir Validate the MyEncoding.txt file, containing the New Number List.
From the previous list all "Char.Empty" (\ t) were converted to char null '\ 0'.
As long as I go through the list from left to right column by column,
I extract the characters from the List, depending on the width of the Model in the Dictionary (ex NumberOne has width 2, NumberFour has width 5).
Each extract will be saved in a new file in Dir Extract
Compare each character in the lists if they are identical. If they are valid then the extracted model will be saved in a file in Dir Validated with the name of a recognized Model name,
and this file will be opened with Notepad for a few seconds, after which notepad will close and the search process will be repeated until the end of the List.
The solutions to this approaches can be found here!

Related

Is there a way to remove a character from a string in this program?

I am tasked with reading the first character in the sentence and count how many times that character occurs. I must then move on to the next character that has not been counted yet and
static void Main(string[] args)
{
char[] array = fullword.ToCharArray();
foreach (char ch in array)
{
Console.WriteLine(GetHowManyTimeOccurenceCharInString(fullword, ch));
}
}
public static int GetHowManyTimeOccurenceCharInString(string text, char c)
{
int count = 0;
foreach (char ch in text)
{
if (ch.Equals(c))
{
count++;
}
}
return count;
}
}
Ok here it is. Just a little program to show you how to do that. First convert your string into a Char arrar and add that to a List. Then you can remove chars from the list using the RemoveAt(n) method. Finally you change your list into a string again and voila there are "JackandJill" again.
using System;
using System.Collections.Generic;
using System.Text;
namespace RemoveChars
{
internal class Program
{
static void Main(string[] args)
{
string name = "Jack and Jill";
var list = new List<char>();
list.AddRange(name.ToCharArray());
list.RemoveAt(4);
list.RemoveAt(7);
var sb = new StringBuilder();
list.ForEach(x => sb.Append(x));
Console.WriteLine(sb.ToString());
Console.ReadKey();
}
}
}
I believe you are trying to get the number of character occurrences in a string.
This will give you a dictionary of character and count.
public Dictionary<char, int> GetNoOfOccurenceCharInString(string stringToCheck)
{
//Track the character and count in a Dictionary.
Dictionary<char, int> map = new Dictionary<char, int>();
//For String "Jack and Jill" it will store something like this in the memory
// j =2, a = 2, c = 1, k = 1, " " = 2, n = 1, d = 1, i = 1, l = 2
//Shift to Lower case and Loop through each character
foreach (var c in stringToCheck.ToLower())
{
if (c == ' ') //If the current char is a space do not count;
{
continue;
}
//Check if map already has the char, if yes use the count stored in the memory, else initialize to 0
var count = map.ContainsKey(c) ? map[c] : 0;
map[c] = count + 1; //Increment count by 1
}
return map;
}
To test this:
string name1 = "Jack";
string matches = "matches";
string name2 = "Jill";
string fullword = name1 + matches + name2;
//Call our method
var result = GetNoOfOccurenceCharInString(fullword);
//loop through each key in the Dictionary
foreach (var key in result.Keys)
{
//Print out the Key and the Count
Console.WriteLine($"{key}: {result[key]}");
}
The best way to do what you need is to create a counting HashMap. I will put this example made in java.
public static void main(String[] args) {
String name1 = "jack";
String matches = "matches";
String name2 = "jill";
String fullWord = name1 + matches + name2;
//Map to get the number of repeated characters
HashMap<Character, Integer> counts = new HashMap<>();
//New string without repeated characters
StringBuilder noRepeatingCharacter = new StringBuilder();
// Text string with the number of repeated characters
StringBuilder literalCounts = new StringBuilder();
for (int i = 0; i < fullWord.length(); i++) {
//We get the character to establish if it is repeated or not.
char charAr = fullWord.charAt(i);
//We verify if in our map the character exists
if (counts.containsKey(charAr)) {
// Update counts
counts.replace(charAr, counts.get(charAr) + 1);
} else {
// we add to our new string of characters only the non-repeated ones
noRepeatingCharacter.append(charAr);
// If the character does not exist in our map, we add it
counts.put(charAr, 1);
}
}
// So that we can print the count in order, we assign to our variable literalCounts
for (int i = 0; i < noRepeatingCharacter.length(); i++) {
char charAr = noRepeatingCharacter.charAt(i);
literalCounts.append(counts.get(charAr));
}
// Print counts
System.out.println("Counts: " + literalCounts);
}
Output
Output

Reverse word of full sentence using for loop in c#

I want to print the string in reverse format in for loop:
Input: I'm Learning c#
Output: c# Learning I'm
No Split functions and reverse functions should be used, it has to do only with forloop.
for (int i = m.Length - 1; i >= 0; i--)
{
b[j]=a[i];
j++;
if(a[i]==' '|| a[i]==0)
{
for (int x = b.Length - 1; x >= 0; x--)
{
c[k] = b[x];
Console.Write(c[k]);
k++;
}
}
} Console.ReadKey();
You have to create an array of the words in the sentence:
var words = input.Split(' ');
Then you just loop through the above array from the end to the start:
for(int i=words.Length-1; i>=0; i--)
{
Console.Write(words[i]+" ");
}
With LINQ and string methods you can simplify it:
var reversedWords = input.Split().Reverse(); // Split without parameters will use space, tab and new-line characters as delimiter
string output = string.Join(" ", reversedWords); // build reversed words, space is delimiter
Use Stack<Queue<char>>
Hey if you want to show off your knowledge of data structures, use a queue and a stack! This makes for a very concise answer as well.
You want the sentence to be LIFO with respect to words but FIFO with respect to letters within words, so you need a stack (which are LIFO) of queues (which are FIFO). You can take advantage of the fact that a string, a queue<char>, and a stack<char> all expose IEnumerable<char> as well, so it's easy to convert back and forth; once you have all the characters ordered in your data structure, you can extract the whole thing as a character array using SelectMany(), which you can pass to a string constructor for the final answer.
This solution uses no Split() or Reverse() functions, as required.
public static string ReverseSentence(string input)
{
var word = new Queue<char>();
var sentence = new Stack<IEnumerable<char>>( new [] { word } );
foreach ( char c in input )
{
if (c == ' ')
{
sentence.Push( " " );
sentence.Push( word = new Queue<char>() );
}
else
{
word.Enqueue(c);
}
}
return new string( sentence.SelectMany( w => w ).ToArray() );
}
Usage:
public void Test()
{
var input = "I'm Learning c#";
var output = ReverseSentence(input);
Console.WriteLine(output);
}
Output:
c# Learning I'm
DotNetFiddle
Without split and reverse, I modify your logic little bit to achieve what you need
namespace MyNamespace
{
public class Program
{
public static void Main(string[] args)
{
var m="this is mystring";
var b = new char [m.Length];
var j=0;
//Your code goes here
for (int i = m.Length - 1; i >= 0; i--)
{
b[j]=m[i];
j++;
if(m[i]==' ' || i==0)
{
if(i==0)
{
b[j]=' ';
}
for (int x = b.Length - 1; x >= 0; x--)
{
Console.Write(b[x]);
}
b=new char[m.Length];
j=0;
}
}
Console.ReadKey();
Console.WriteLine("Hello, world!");
}
}
}
Input: "this is mystring"
Output: "mystring is this"
Here is a simple console application for your question
Without using Reverse and Split methods (just for loop)
class Program
{
static void Main()
{
string input = "I'm learning C#";
string[] result = new string[3];
int arrayIndex = 0;
string tempStr = "";
// Split string
for (int i = 0; i < input.Length; i++)
{
tempStr += input[i].ToString();
if (input[i] != ' ')
{
result[arrayIndex] = tempStr;
}
else
{
tempStr = "";
arrayIndex++;
}
}
// Display Result
for (int i = result.Length - 1; i >= 0; i--)
{
System.Console.Write(result[i] + ' ');
}
System.Console.WriteLine();
}
}
Press Ctrl + F5 to run the program
Output: C# learning I'm

How to check for 3 consequtive letters in a string?

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.

How to reverse an array of strings without changing the position of special characters in C#

I'm working on reversing a sentence. I'm able to do it. But I'm not sure, how to reverse the word without changing the special characters positions. I'm using regex but as soon as it finds the special characters it's stopping the reversal of the word.
Following is the code:
Console.WriteLine("Enter:");
string w = Console.ReadLine();
string rw = String.Empty;
String[] arr = w.Split(' ');
var regexItem = new Regex("^[a-zA-Z0-9]*$");
StringBuilder appendString = new StringBuilder();
for (int i = 0; i < arr.Length; i++)
{
char[] chararray = arr[i].ToCharArray();
for (int j = chararray.Length - 1; j >= 0; j--)
{
if (regexItem.IsMatch(rw))
{
rw = appendString.Append(chararray[j]).ToString();
}
}
sb.Append(' ');
}
Console.WriteLine(rw);
Console.ReadLine();
Example : Input
Marshall! Hello.
Expected output
llahsram! olleh.
A basic solution with regex and LINQ. Try it online.
public static void Main()
{
Console.WriteLine("Marshall! Hello.");
Console.WriteLine(Reverse("Marshall! Hello."));
}
public static string Reverse(string source)
{
// we split by groups to keep delimiters
var parts = Regex.Split(source, #"([^a-zA-Z0-9])");
// if we got a group of valid characters
var results = parts.Select(x => x.All(char.IsLetterOrDigit)
// we reverse it
? new string(x.Reverse().ToArray())
// or we keep the delimiters as it
: x);
// then we concat all of them
return string.Concat(results);
}
The same solution without LINQ. Try it online.
public static void Main()
{
Console.WriteLine("Marshall! Hello.");
Console.WriteLine(Reverse("Marshall! Hello."));
}
public static bool IsLettersOrDigits(string s)
{
foreach (var c in s)
{
if (!char.IsLetterOrDigit(c))
{
return false;
}
}
return true;
}
public static string Reverse(char[] s)
{
Array.Reverse(s);
return new string(s);
}
public static string Reverse(string source)
{
var parts = Regex.Split(source, #"([^a-zA-Z0-9])");
var results = new List<string>();
foreach(var x in parts)
{
results.Add(IsLettersOrDigits(x)
? Reverse(x.ToCharArray())
: x);
}
return string.Concat(results);
}
This is a solution without LINQ. I wasn't sure about what are considered special characters.
string sentence = "Marshall! Hello.";
List<string> words = sentence.Split(' ').ToList();
List<string> reversedWords = new List<string>();
foreach (string word in words)
{
char[] arr = new char[word.Length];
for( int i=0; i<word.Length; i++)
{
if(!Char.IsLetterOrDigit((word[i])))
{
for ( int x=0; x< i; x++)
{
arr[x] = arr[x + 1];
}
arr[i] = word[i];
}
else
{
arr[word.Length - 1 - i] = word[i];
}
}
reversedWords.Add(new string(arr));
}
string reversedSentence = string.Join(" ", reversedWords);
Console.WriteLine(reversedSentence);
And this is the output:
Updated Output = llahsraM! olleH.
Here is a non-regex version that does what you want:
var sentence = "Hello, john!";
var parts = sentence.Split(' ');
var reversed = new StringBuilder();
var charPositions = sentence.Select((c, idx) => new { Char = c, Index = idx })
.Where(_ => !char.IsLetterOrDigit(_.Char));
for (int i = 0; i < parts.Length; i++)
{
var chars = parts[i].ToCharArray();
for (int j = chars.Length - 1; j >= 0; j--)
{
if (char.IsLetterOrDigit(chars[j]))
{
reversed.Append(chars[j]);
}
}
}
foreach (var ch in charPositions)
{
reversed.Insert(ch.Index, ch.Char);
}
// olleH, nhoj!
Console.WriteLine(reversed.ToString());
Basically the trick is to remember the position of special (i.e. non letter or digit) characters and insert them at the end to those positions.
This solution is without LINQ and Regex. It may not be an efficient answer but working properly for small string values.
// This will reverse the string and special characters will just stay there.
public string ReverseString(string rString)
{
StringBuilder ss = new StringBuilder(rString);
int y = 0;
// The idea is to swap values. Like swapping first value with last one. It will keep swapping unless it reaches at the middle of the string where no swapping will be needed.
// This first loop is to detect first values.
for(int i=rString.Length-1;i>=0;i--)
{
// This condition is to check if the values is String or not. If it is not string then it is considered as special character which will just stay there at same old position.
if(Char.IsLetter(Convert.ToChar(rString.Substring(i,1))))
{
// This is second loop which is starting from end to swap values from end with first.
for (int k = y; k < rString.Length; k++)
{
// Again checking last values if values are string or not.
if (Char.IsLetter(Convert.ToChar(rString.Substring(k, 1))))
{
// This is swapping. So st1 is First value in that string
// st2 is the last item in that string
char st1 = Convert.ToChar(rString.Substring(k, 1));
char st2 = Convert.ToChar(rString.Substring(i, 1));
//This is swapping. So last item will go to first position and first item will go to last position, To make sure string is reversed.
// Remember when the string value is Special Character, swapping will move forward without swapping.
ss[rString.IndexOf(rString.Substring(i, 1))] = st1;
ss[rString.IndexOf(rString.Substring(k, 1))] = st2;
y++;
// When the swapping is done for first 2 items. The loop will stop to change the values.
break;
}
else
{
// This is just increment if value was Special character.
y++;
}
}
}
}
return ss.ToString();
}
Thanks!

Iterating through 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".

Categories