Detecting Filename Patterns for Creating RegEx - c#

When using a string to define a RegEx, I'd like to know if there is a way to get my code to recognize a pattern in the files contained within a directory.
The goal is to rename these files using our naming conventions, so I'm writing something to try to create the expression to use in RegEx.
I've started something here, but I don't think it is the best, and I'm not sure how to fill in the "{0}" portion of my RegEx expression.
private Regex m_regex;
public string DirPattern(string path, string[] extensions) {
string result = null;
int endPos = 0;
int resLen = 0;
int startLen = 0;
var dir = new DirectoryInfo(path);
foreach (var file in dir.GetFiles()) {
if (extensions.Contains(file.Extension)) {
if (!String.IsNullOrEmpty(result)) {
int sL = 0;
int fileLen = file.Name.Length;
string one = null;
for (int i = 0; i < resLen && i < fileLen; i++) {
if (result[i] == file.Name[i]) {
sL = i + 1;
if (String.IsNullOrEmpty(one)) {
one = file.Name;
} else {
break;
}
}
}
if (!String.IsNullOrEmpty(one)) {
int eP = 0;
int oneLen = one.Length;
for (int i = fileLen - 1; -1 < i; i--) {
if (result[i] == file.Name[i]) {
eP = i - 1;
} else {
break;
}
}
if ((0 < endPos) && (eP == endPos)) {
if ((0 < startLen) && (sL == startLen)) {
result = one.Substring(0, startLen) + "{0}" + one.Substring(endPos);
} else if (0 < sL) {
startLen = sL;
}
} else if (0 < sL) {
startLen = sL;
}
}
} else {
result = file.Name;
resLen = result.Length;
}
}
}
return result;
}
public bool GenerateRexEx(string path, string[] extensions) {
var pattern = DirPattern(path, extensions);
if (!String.IsNullOrEmpty(pattern)) {
m_regex = new Regex(pattern);
return true;
}
return false;
}
Here is an example of a list of files that would be most like our company files (which I am not allowed to post):
UPDATE:
The goal is to take files with names like this:
FOLDER_PATTERN_1 + MixedContent + FOLDER_PATTERN_2
and rename them using our format:
OUR_PATTERN_1 + MixedContent + OUR_PATTERN_2
That way, our software will be able to search the files more efficiently.

I think that in your case you need just to find count of characters in the prefix pattern and postfix pattern. Then you can simply replace some count of characters with your pattern. I wrote a simple code which I tested and works. You can inspire yourself and use the same method I think. Anyway there are areas to make this better, but I hope it is enough to answer your question.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
static class Program
{
static void Main()
{
var inputFilenames = new string[]
{
"mtn_flint501-muxed",
"mtn_flint502-muxed",
"mtn_flint503-muxed",
"mtn_flint504-muxed",
"mtn_flint505-muxed",
"mtn_flint506-muxed",
"mtn_flint507-muxed",
"mtn_flint508-muxed",
"mtn_flint509-muxed",
"mtn_flint510-muxed",
"mtn_flint511-muxed",
"mtn_flint512-muxed",
};
var replacedFilenames = ReplaceFileNames(inputFilenames);
for (int i = 0; i < inputFilenames.Length; i++)
{
Console.WriteLine("{0} >> {1}", inputFilenames[i], replacedFilenames[i]);
}
Console.ReadKey();
}
private const string OurPrefixPattern = "Prefix_";
private const string OurPostfixPattern = "_Postfix";
/// <summary>
/// Method which will find the filename's pattern and replace it with our pattern
/// </summary>
/// <param name="fileNames"></param>
/// <returns></returns>
public static string[] ReplaceFileNames(params string[] fileNames)
{
//At first, we will find count of characters, which are same for
//all filenames as prefix and store it to prefixCount variable and
//we will find count of characters which are same for all filenames
//as postfix and store it to postfixCount variable
var prefixCount = int.MaxValue;
var postfixCount = int.MaxValue;
//We will use first filename as the reference one (we will be comparing)
//all filenames with this one
var referenceFilename = fileNames[0];
var reversedReferenceFilename = referenceFilename.ReverseString();
//Lets find the prefixCount and postfixCount
foreach (var filename in fileNames)
{
if (filename == referenceFilename)
{
continue;
}
//Check for prefix count
var firstDifferenceIndex = referenceFilename.GetFirstDifferentIndexWith(filename);
if (firstDifferenceIndex < prefixCount)
{
prefixCount = firstDifferenceIndex;
}
//For postfix count we will do the same, but with reversed strings
firstDifferenceIndex = reversedReferenceFilename.GetFirstDifferentIndexWith(filename.ReverseString());
if (firstDifferenceIndex < postfixCount)
{
postfixCount = firstDifferenceIndex;
}
}
//So now replace given filnames with our prefix and post fix.
//Our regex determines only how many characters should be replaced
var prefixRegexToReplace = string.Format("^.{{{0}}}", prefixCount);
var postfixRegexToReplace = string.Format(".{{{0}}}$", postfixCount);
var result = new string[fileNames.Length];
for (int i = 0; i < fileNames.Length; i++)
{
//Replace the prefix
result[i] = Regex.Replace(fileNames[i], prefixRegexToReplace, OurPrefixPattern);
//Replace the postfix
result[i] = Regex.Replace(result[i], postfixRegexToReplace, OurPostfixPattern);
}
return result;
}
/// <summary>
/// Gets the first index in which the strings has different character
/// </summary>
/// <param name="value"></param>
/// <param name="stringToCompare"></param>
/// <returns></returns>
private static int GetFirstDifferentIndexWith(this string value, string stringToCompare)
{
return value.Zip(stringToCompare, (c1, c2) => c1 == c2).TakeWhile(b => b).Count();
}
/// <summary>
/// Revers given string
/// </summary>
/// <param name="value">String which should be reversed</param>
/// <returns>Reversed string</returns>
private static string ReverseString(this string value)
{
char[] charArray = value.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
}
}
The console output looks like this
mtn_flint501-muxed >> Prefix_01_Postfix
mtn_flint502-muxed >> Prefix_02_Postfix
mtn_flint503-muxed >> Prefix_03_Postfix
mtn_flint504-muxed >> Prefix_04_Postfix
mtn_flint505-muxed >> Prefix_05_Postfix
mtn_flint506-muxed >> Prefix_06_Postfix
mtn_flint507-muxed >> Prefix_07_Postfix
mtn_flint508-muxed >> Prefix_08_Postfix
mtn_flint509-muxed >> Prefix_09_Postfix
mtn_flint510-muxed >> Prefix_10_Postfix
mtn_flint511-muxed >> Prefix_11_Postfix
mtn_flint512-muxed >> Prefix_12_Postfix

Related

How to take X amount of questions, that sum up Y amount of difficulty

I have a table
Questions -> Question(string), Difficulty (int, 1-10)
I need to create a method, that as the title mentions, takes X amount of questions, whose difficulty should sum up Y.
For example:
getQuestions(2,10) -> Question1 (diff: 4), Question2 (diff: 6)
getQuestions(3,15) -> Question3 (diff: 5), Question4 (diff: 5), Question5 (diff: 5)
How can I achieve something like this with LINQ?
Here's one way to do it, using a modified version of the recursive solution found here: Finding all possible combinations of numbers to reach a given sum
First, a public method that will do some quick validation and then call a recursive method to get the results:
/// <summary>
/// Gets lists of numQuestions length of all combinations
/// of questions whose difficulties add up to sumDifficulty
/// </summary>
/// <param name="questions">The list of questions to search</param>
/// <param name="numQuestions">The number of questions required</param>
/// <param name="sumDifficulty">The amount that the difficulties should sum to</param>
/// <returns></returns>
public static List<List<Question>> GetQuestions(List<Question> questions,
int numQuestions, int sumDifficulty)
{
if (questions == null) throw new ArgumentNullException("questions");
var results = new List<List<Question>>();
// Fail fast argument validation
if (numQuestions < 1 ||
numQuestions > questions.Count ||
sumDifficulty < numQuestions * Question.MinDifficulty ||
sumDifficulty > numQuestions * Question.MaxDifficulty)
{
return results;
}
// If we only need single questions, no need to do any recursion
if (numQuestions == 1)
{
results.AddRange(questions.Where(q => q.Difficulty == sumDifficulty)
.Select(q => new List<Question> {q}));
return results;
}
// We can remove any questions who have a difficulty that's higher
// than the sumDifficulty minus the number of questions plus one
var candidateQuestions =
questions.Where(q => q.Difficulty <= sumDifficulty - numQuestions + 1)
.ToList();
if (!candidateQuestions.Any())
{
return results;
}
GetSumsRecursively(candidateQuestions, sumDifficulty, new List<Question>(),
numQuestions, results);
return results;
}
And then the recursive method that does the heavy lifting:
private static void GetSumsRecursively(IReadOnlyList<Question> questions,
int sumDifficulty, List<Question> candidates, int numQuestions,
ICollection<List<Question>> results)
{
int candidateSum = candidates.Sum(x => x.Difficulty);
if (candidateSum == sumDifficulty && candidates.Count == numQuestions)
{
results.Add(candidates);
}
if (candidateSum >= sumDifficulty)
return;
for (int i = 0; i < questions.Count; i++)
{
var remaining = new List<Question>();
for (int j = i + 1; j < questions.Count; j++)
{
remaining.Add(questions[j]);
}
var filteredCandidates = new List<Question>(candidates) {questions[i]};
GetSumsRecursively(remaining, sumDifficulty, filteredCandidates,
numQuestions, results);
}
}
Here's an example usage:
public static void Main()
{
const int numberOfQuestions = 3;
const int sumOfDifficulty = 15;
// Since I don't have your table, I'm using a list of objects to fake it
var questions = new List<Question>();
for (int i = 1; i < 11; i++)
{
questions.Add(new Question {Difficulty = i % 10 + 1,
QuestionString = "Question #" + i});
}
var results = GetQuestions(questions, numberOfQuestions, sumOfDifficulty);
// Write output to console to verify results
foreach (var result in results)
{
Console.WriteLine("{0} = {1}", string.Join(" + ",
result.Select(r => r.Difficulty)), sumOfDifficulty);
}
}
And just so you have everything to make this work, here's my Question class used to fake your table:
internal class Question
{
public const int MinDifficulty = 1;
public const int MaxDifficulty = 10;
private int _difficulty;
public int Difficulty
{
get { return _difficulty; }
set
{
if (value < MinDifficulty) _difficulty = MinDifficulty;
else if (value > MaxDifficulty) _difficulty = MaxDifficulty;
else _difficulty = value;
}
}
public string QuestionString { get; set; }
}

Comparison of multi-part alphanumeric strings

I receive a string which contains the sw version currently running in the system.
I want to do some operations only if the system is running on a certain sw version or
later.
e.g. If system is running sw version 2.D or later (2.E, ..) I do some operations. If system is running lower sw version (2.C, ..), then I don't do it.
How to do this comparison for strings?
There are many ways of doing this, but if you know that the string is in the form x.y or even x.y.z... then I would suggest using a custom StringComparer:
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace StingComparisons
{
[TestClass]
public class StringComparison
{
[TestMethod]
public void TestMethod1()
{
var a = "2.E";
var b = "2.F";
var c = "2.C";
var d = "1.F";
var e = "3.A";
StringComparer comp = new MyStringComparer();
Assert.IsTrue(b.IsSameOrAfter(a, comp));
Assert.IsFalse(c.IsSameOrAfter(a, comp));
Assert.IsFalse(d.IsSameOrAfter(a, comp));
Assert.IsTrue(e.IsSameOrAfter(a, comp));
Assert.IsTrue(a.IsSameOrAfter(a, comp));
}
[TestMethod]
public void TestMethod2()
{
var a = "2.E.1";
var b = "2.E";
var c = "2.E.2";
var d = "2.F";
var e = "2.D.3";
var f = "3.A";
StringComparer comp = new MyStringComparer();
Assert.IsFalse(b.DotDelimitedIsSameOrAfter(a));
Assert.IsTrue(c.DotDelimitedIsSameOrAfter(a));
Assert.IsTrue(d.DotDelimitedIsSameOrAfter(a));
Assert.IsFalse(e.DotDelimitedIsSameOrAfter(a));
Assert.IsTrue(f.DotDelimitedIsSameOrAfter(a));
Assert.IsTrue(a.DotDelimitedIsSameOrAfter(a));
}
}
public static class stringExtensions
{
public static bool DotDelimitedIsSameOrAfter(this string a, string b)
{
return a.IsSameOrAfter(b, new MyStringComparer());
}
public static bool IsSameOrAfter(this string a, string b, StringComparer comp)
{
return comp.Compare(a, b) <= 0;
}
}
public class MyStringComparer : StringComparer
{
public override int Compare(string x, string y)
{
var partsX = x.Split('.');
var partsY = y.Split('.');
for (int i = 0; i < partsY.Length; i++)
{
if (partsX.Length <= i)
return 1;
var partComp = partsY[i].CompareTo(partsX[i]);
if (partComp != 0)
return partComp;
}
return 0;
}
public override bool Equals(string x, string y)
{
return x.Equals(y);
}
public override int GetHashCode(string obj)
{
return obj.GetHashCode();
}
}
}
I have wrapped the calls in an extension method purely to make it a bit more readable.
Since I was needing just that (and a bit more), I've written the following comparer which compares two alphanumeric version strings:
/// <summary>
/// Compares two alphanumeric version numbers.
/// </summary>
public class AlphanumericVersionComparer : IComparer<string>
{
/// <summary>
/// Compares two alphanumeric version numbers and returns a value
/// indicating whether one is less than, equal to, or greater than the other.
/// </summary>
/// <param name="x">The first alphanumeric version number to compare.</param>
/// <param name="y">The second alphanumeric version number to compare.</param>
/// <returns>A signed integer that indicates the relative values of x and y.</returns>
public int Compare(string x, string y)
{
// Validate parameters
if (x == null) throw new ArgumentNullException("x");
if (y == null) throw new ArgumentNullException("y");
// Test for equality
if (x == y)
return 0;
// Split the different parts of the number
string[] xParts = x.Split('.');
string[] yParts = y.Split('.');
// Compare each parts
AlphanumericComparer alphaNumComparer = new AlphanumericComparer();
for (int i = 0, n = Math.Max(xParts.Length, yParts.Length); i < n; i++)
{
// If the part at index i is not in y => x is greater
if (i >= yParts.Length)
return 1;
// If the part at index i is not in x => y is greater
if (i >= xParts.Length)
return -1;
// Compare the two alphanumerical numbers
int result = alphaNumComparer.Compare(xParts[i], yParts[i]);
if (result != 0)
{
return result;
}
}
// The two numbers are equal (really??? I thought we tested for equality already!)
System.Diagnostics.Debug.Fail("Not supposed to reach this code...");
return 0;
}
}
/// <summary>
/// Compares two alphanumeric strings.
/// </summary>
/// <remarks>See http://snipd.net/alphanumericnatural-sorting-in-c-using-icomparer </remarks>
public class AlphanumericComparer : IComparer<string>
{
/// <summary>
/// Compares two alphanumerics and returns a value
/// indicating whether one is less than, equal to, or greater than the other.
/// </summary>
/// <param name="x">The first alphanumeric to compare.</param>
/// <param name="y">The second alphanumeric to compare.</param>
/// <returns>A signed integer that indicates the relative values of x and y.</returns>
public int Compare(string x, string y)
{
int len1 = x.Length;
int len2 = y.Length;
int marker1 = 0;
int marker2 = 0;
// Walk through two the strings with two markers.
while (marker1 < len1 && marker2 < len2)
{
char ch1 = x[marker1];
char ch2 = y[marker2];
// Some buffers we can build up characters in for each chunk.
char[] space1 = new char[len1];
int loc1 = 0;
char[] space2 = new char[len2];
int loc2 = 0;
// Walk through all following characters that are digits or
// characters in BOTH strings starting at the appropriate marker.
// Collect char arrays.
do
{
space1[loc1++] = ch1;
marker1++;
if (marker1 < len1)
{
ch1 = x[marker1];
}
else
{
break;
}
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
do
{
space2[loc2++] = ch2;
marker2++;
if (marker2 < len2)
{
ch2 = y[marker2];
}
else
{
break;
}
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
// If we have collected numbers, compare them numerically.
// Otherwise, if we have strings, compare them alphabetically.
string str1 = new string(space1);
string str2 = new string(space2);
int result;
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
{
int thisNumericChunk = int.Parse(str1);
int thatNumericChunk = int.Parse(str2);
result = thisNumericChunk.CompareTo(thatNumericChunk);
}
else
{
result = str1.CompareTo(str2);
}
if (result != 0)
{
return result;
}
}
return len1 - len2;
}
}
You can play with the fiddle here: https://dotnetfiddle.net/28iius.
All credits to http://snipd.net/alphanumericnatural-sorting-in-c-using-icomparer for the alphanumeric comparison.

StackOverFlowException thrown only when multi-threading

I'm writing a program to help me gather statistics for a research report I'm writing on password security. I decided to make the application run on multiple threads when attempted to brute-force an MD5 hashed password for the obvious performance increase. The application runs fine on a single thread, but the moment 2 threads are running, a StackOverFlowException is throwing at "using (MD5 md5Hash = MD5.Create())" in the TryPass function.
// Microsoft's GetMd5Hash function.
static string GetMd5Hash(MD5 md5Hash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
static bool TryPass(string attempt, string password)
{
using (MD5 md5Hash = MD5.Create())
{
if (GetMd5Hash(md5Hash, attempt) == password)
return true;
else
return false;
}
}
static bool BruteForce(BruteOptions bruteOptions)
{
if (bruteOptions.prefix.Length == 1 && TryPass(bruteOptions.prefix, bruteOptions.password)) // If it's the first in a series, try it.
return true;
for (int i = 0; i < bruteOptions.chars.Length; i++)
{
if (TryPass(bruteOptions.prefix + bruteOptions.chars[i], bruteOptions.password))
{
Console.WriteLine("The password is: " + bruteOptions.prefix + bruteOptions.chars[i]);
return true;
}
if (bruteOptions.prefix.Length + 1 < bruteOptions.maxLength)
if (BruteForce(bruteOptions))
return true;
//Console.WriteLine(prefix + chars[i]);
}
return false;
}
public struct BruteOptions
{
public string password, prefix;
public char[] chars;
public int maxLength;
}
static void OptionBruteForce()
{
Console.WriteLine("-----------------------");
Console.WriteLine("----- Brute-Force -----");
Console.WriteLine("-----------------------");
BruteOptions bruteOptions = new BruteOptions();
bruteOptions.password = ReadString("Enter the MD5 password hash to brute-force: ");
bruteOptions.chars = ReadString("Enter the characters to use: ").ToCharArray();
bruteOptions.maxLength = ReadIntegerRange("Max length of password: ", 1, 16);
bruteOptions.prefix = "";
Stopwatch myStopWatch = Stopwatch.StartNew();
int NUM_THREADS = bruteOptions.chars.Length;
Thread[] workers = new Thread[NUM_THREADS]; // Run a thread for each char.
var countdownEvent = new CountdownEvent(NUM_THREADS);
bool result = false;
// Start workers.
for (int i = 0; i < NUM_THREADS; i++)
{
int index = i;
BruteOptions newBruteOptions = bruteOptions;
newBruteOptions.prefix = bruteOptions.chars[index].ToString();
workers[index] = new Thread(delegate()
{
// Also check single char.
if (BruteForce(bruteOptions))
{
result = true;
// End all other threads.
for (int ii = 0; ii < NUM_THREADS; ii++)
{
if (workers[ii].ThreadState == System.Threading.ThreadState.Running && index != ii) // Ensures we don't prematurely abort this thread.
{
workers[ii].Abort();
countdownEvent.Signal(); // Signal so we can zero it and continue on the UI thread.
}
}
}
// Signal the CountdownEvent.
countdownEvent.Signal();
});
workers[index].Start();
}
// Wait for workers.
countdownEvent.Wait();
if (!result)
Console.WriteLine("No Match.");
Console.WriteLine("Took " + myStopWatch.ElapsedMilliseconds + " Milliseconds");
}
That's all the relevant code. Any insight onto why this is happening would be greatly appreciated! I'm completely stumped. I attempted to specify a greater stack size when initialising each thread, to no avail.
Thanks in advance!
Your static bool BruteForce(BruteOptions bruteOptions) is infinitely recursive: it calls itself if the length allows, with the same parameters:
if (bruteOptions.prefix.Length + 1 < bruteOptions.maxLength)
if (BruteForce(bruteOptions))
bruteOptions remain the same as it was on the entry to the function.
As a solution you may use this code:
if (bruteOptions.prefix.Length + 1 < bruteOptions.maxLength)
{
BruteOptions newOptions = bruteOptions;
newOptions.prefix += bruteOptions.chars[i];
if (BruteForce(newOptions))
return true;
}
Plus, you pass bruteOptions, not newBruteOptions to the delegate you use in main function. Thus, your multithreading is not used, in fact. All your threads test the same passwords. Change it to newBruteOptions.
Additionally, don't assume anything about threads execution order. You assume that all workers are filled by the moment one finds a proper password, which can be wrong. You will then get a NullReferenceException in this line:
if (workers[ii].ThreadState == System.Threading.ThreadState.Running && index != ii) // Ensures we don't prematurely abort this thread.
I'm guessing your single threaded code looked a little different.
I would lose the recursion.
Just for kicks, here's an alternate implementation without the recursion and making a bit better use of the language constructs and frameworks available as part of .Net
class Program
{
private static string StringFromIndexPermutation(char[] characters, int[] indexes)
{
var buffer = new char[indexes.Length];
for (var i = 0; i < buffer.Length; ++i)
{
buffer[i] = characters[indexes[i]];
}
return new string(buffer);
}
/// <summary>
/// Increments a set of "digits" in a base "numberBase" number with the MSD at position 0
/// </summary>
/// <param name="buffer">The buffer of integers representing the numeric string</param>
/// <param name="numberBase">The base to treat the digits of the number as</param>
/// <returns>false if the number in the buffer has just overflowed, true otherwise</returns>
private static bool Increment(int[] buffer, int numberBase)
{
for (var i = buffer.Length - 1; i >= 0; --i)
{
if ((buffer[i] + 1) < numberBase)
{
++buffer[i];
return true;
}
buffer[i] = 0;
}
return false;
}
/// <summary>
/// Calculate all the permutations of some set of characters in a string from length 1 to maxLength
/// </summary>
/// <param name="characters">The characters to permute</param>
/// <param name="maxLength">The maximum length of the permuted string</param>
/// <returns>The set of all permutations</returns>
public static IEnumerable<string> Permute(char[] characters, int maxLength)
{
for (var i = 0; i < maxLength; ++i)
{
var permutation = new int[i + 1];
yield return StringFromIndexPermutation(characters, permutation);
while (Increment(permutation, characters.Length))
{
yield return StringFromIndexPermutation(characters, permutation);
}
}
}
static string ReadString(string message)
{
Console.Write(message);
return Console.ReadLine();
}
private static int ReadIntegerRange(string message, int min, int max)
{
Console.Write(message + "({0} - {1})", min, max);
while(true)
{
var test = Console.ReadLine();
int value;
if (int.TryParse(test, out value))
{
return value;
}
}
return -1;
}
static void OptionBruteForce()
{
Console.WriteLine("-----------------------");
Console.WriteLine("----- Brute-Force -----");
Console.WriteLine("-----------------------");
var password = ReadString("Enter the MD5 password hash to brute-force: ");
var chars = ReadString("Enter the characters to use: ").Distinct().ToArray();
var maxLength = ReadIntegerRange("Max length of password: ", 1, 16);
var myStopWatch = Stopwatch.StartNew();
var result = false;
string match = null;
var cancellationTokenSource = new CancellationTokenSource();
var passwordBytes = Encoding.Default.GetBytes(password);
var originalMd5 = MD5.Create();
var passwordHash = originalMd5.ComputeHash(passwordBytes);
var hashAlgGetter = new ConcurrentDictionary<Thread, MD5>();
try
{
Parallel.ForEach(Permute(chars, maxLength), new ParallelOptions
{
CancellationToken = cancellationTokenSource.Token
}, test =>
{
var md5 = hashAlgGetter.GetOrAdd(Thread.CurrentThread, t => MD5.Create());
var data = Encoding.Default.GetBytes(test);
var hash = md5.ComputeHash(data);
if (hash.SequenceEqual(passwordHash))
{
myStopWatch.Stop();
match = test;
result = true;
cancellationTokenSource.Cancel();
}
});
}
catch (OperationCanceledException)
{
}
if (!result)
{
Console.WriteLine("No Match.");
}
else
{
Console.WriteLine("Password is: {0}", match);
}
Console.WriteLine("Took " + myStopWatch.ElapsedMilliseconds + " Milliseconds");
}
static void Main()
{
OptionBruteForce();
Console.ReadLine();
}
}

String concatenate/shorten algorithm

I want to publish server-messages on Twitter, for our clients.
Unfortunately, Twitter only allows posting 140 Chars or less. This is a shame.
Now, I have to write an algorithm that concatenates the different messages from the server together, but shortens them to a max of 140 characters.
It's pretty tricky.
CODE
static string concatinateStringsWithLength(string[] strings, int length, string separator) {
// This is the maximum number of chars for the strings
// We have to subtract the separators
int maxLengthOfAllStrings = length - ((strings.Length - 1) * separator.Length);
// Here we save all shortenedStrings
string[] cutStrings = new string[strings.Length];
// This is the average length of all the strings
int averageStringLenght = maxLengthOfAllStrings / strings.Length;
// Now we check how many strings are longer than the average string
int longerStrings = 0;
foreach (string singleString in strings)
{
if (singleString.Length > averageStringLenght)
{
longerStrings++;
}
}
// If a string is smaller than the average string, we can more characters to the longer strings
int maxStringLength = averageStringLenght;
foreach (string singleString in strings)
{
if (averageStringLenght > singleString.Length)
{
maxStringLength += (int)((averageStringLenght - singleString.Length) * (1.0 / longerStrings));
}
}
// Finally we shorten the strings and save them to the array
int i = 0;
foreach (string singleString in strings)
{
string shortenedString = singleString;
if (singleString.Length > maxStringLength)
{
shortenedString = singleString.Remove(maxStringLength);
}
cutStrings[i] = shortenedString;
i++;
}
return String.Join(separator, cutStrings);
}
Problem with this
This algorithm works, but it's not very optimized.
It uses less characters than it actually could.
The main problem with this is that the variable longerStrings is relative to the maxStringLength, and backwards.
This means if I change longerStrings, maxStringLength gets changed, and so on and so on.
I'd have to make a while loop and do this until there are no changes, but I don't think that's necessary for such a simple case.
Can you give me a clue on how to continue?
Or maybe there already exists something similar?
Thanks!
EDIT
The messages I get from the server look like this:
Message
Subject
Date
Body
Message
Subject
Date
Body
And so on.
What I want is to concatenate the strings with a separator, in this case a semi-colon.
There should be a max length. The long strings should be shortened first.
Example
This is a subject
This is the body and is a bit lon...
25.02.2013
This is a s...
This is the...
25.02.2013
I think you get the idea ;)
Five times slower than yours (in our simple example) but should use maximum avaliable space (no critical values checking):
static string Concatenate(string[] strings, int maxLength, string separator)
{
var totalLength = strings.Sum(s => s.Length);
var requiredLength = totalLength - (strings.Length - 1)*separator.Length;
// Return if there is enough place.
if (requiredLength <= maxLength)
return String.Concat(strings.Take(strings.Length - 1).Select(s => s + separator).Concat(new[] {strings.Last()}));
// The problem...
var helpers = new ConcatenateInternal[strings.Length];
for (var i = 0; i < helpers.Length; i++)
helpers[i] = new ConcatenateInternal(strings[i].Length);
var avaliableLength = maxLength - (strings.Length - 1)*separator.Length;
var charsInserted = 0;
var currentIndex = 0;
while (charsInserted != avaliableLength)
{
for (var i = 0; i < strings.Length; i++)
{
if (charsInserted == avaliableLength)
break;
if (currentIndex >= strings[i].Length)
{
helpers[i].Finished = true;
continue;
}
helpers[i].StringBuilder.Append(strings[i][currentIndex]);
charsInserted++;
}
currentIndex++;
}
var unified = new StringBuilder(avaliableLength);
for (var i = 0; i < strings.Length; i++)
{
if (!helpers[i].Finished)
{
unified.Append(helpers[i].StringBuilder.ToString(0, helpers[i].StringBuilder.Length - 3));
unified.Append("...");
}
else
{
unified.Append(helpers[i].StringBuilder.ToString());
}
if (i < strings.Length - 1)
{
unified.Append(separator);
}
}
return unified.ToString();
}
And ConcatenateInternal:
class ConcatenateInternal
{
public StringBuilder StringBuilder { get; private set; }
public bool Finished { get; set; }
public ConcatenateInternal(int capacity)
{
StringBuilder = new StringBuilder(capacity);
}
}

Is it required to check before replacing a string in StringBuilder (using functions like "Contains" or "IndexOf")?

Is there any method IndexOf or Contains in C#. Below is the code:
var sb = new StringBuilder(mystring);
sb.Replace("abc", "a");
string dateFormatString = sb.ToString();
if (sb.ToString().Contains("def"))
{
sb.Replace("def", "aa");
}
if (sb.ToString().Contains("ghi"))
{
sb.Replace("ghi", "assd");
}
As you might have noticed I am using ToString() above again and again which I want to avoid as it is creating new string everytime. Can you help me how can I avoid it?
If the StringBuilder doesn't contain "def" then performing the replacement won't cause any problems, so just use:
var sb = new StringBuilder(mystring);
sb.Replace("abc", "a");
sb.Replace("def", "aa");
sb.Replace("ghi", "assd");
There's no such method in StringBuilder but you don't need the Contains tests. You can simply write it like this:
sb.Replace("abc", "a");
sb.Replace("def", "aa");
sb.Replace("ghi", "assd");
If the string in the first parameter to Replace is not found then the call to Replace is a null operation—exactly what you want.
The documentation states:
Replaces all occurrences of a specified string in this instance with another specified string.
The way you read this is that when there are no occurrences, nothing is done.
You can write a class that extends methods to the StringBuilder object. Here, I have added IndexOf, Substring, and other methods to the StringBuilder class. Just put this class in your project.
using System;
using System.Text;
namespace Helpers
{
/// <summary>
/// Adds IndexOf, IsStringAt, AreEqual, and Substring to all StringBuilder objects.
/// </summary>
public static class StringBuilderExtension
{
// Adds IndexOf, Substring, AreEqual to the StringBuilder class.
public static int IndexOf(this StringBuilder theStringBuilder,string value)
{
const int NOT_FOUND = -1;
if (theStringBuilder == null)
{
return NOT_FOUND;
}
if (String.IsNullOrEmpty(value))
{
return NOT_FOUND;
}
int count = theStringBuilder.Length;
int len = value.Length;
if (count < len)
{
return NOT_FOUND;
}
int loopEnd = count - len + 1;
for (int loop = 0; loop < loopEnd; loop++)
{
bool found = true;
for (int innerLoop = 0; innerLoop < len; innerLoop++)
{
if (theStringBuilder[loop + innerLoop] != value[innerLoop])
{
found = false;
break;
}
}
if (found)
{
return loop;
}
}
return NOT_FOUND;
}
public static int IndexOf(this StringBuilder theStringBuilder, string value,int startPosition)
{
const int NOT_FOUND = -1;
if (theStringBuilder == null)
{
return NOT_FOUND;
}
if (String.IsNullOrEmpty(value))
{
return NOT_FOUND;
}
int count = theStringBuilder.Length;
int len = value.Length;
if (count < len)
{
return NOT_FOUND;
}
int loopEnd = count - len + 1;
if (startPosition >= loopEnd)
{
return NOT_FOUND;
}
for (int loop = startPosition; loop < loopEnd; loop++)
{
bool found = true;
for (int innerLoop = 0; innerLoop < len; innerLoop++)
{
if (theStringBuilder[loop + innerLoop] != value[innerLoop])
{
found = false;
break;
}
}
if (found)
{
return loop;
}
}
return NOT_FOUND;
}
public static string Substring(this StringBuilder theStringBuilder, int startIndex, int length)
{
return theStringBuilder == null ? null : theStringBuilder.ToString(startIndex, length);
}
public static bool AreEqual(this StringBuilder theStringBuilder, string compareString)
{
if (theStringBuilder == null)
{
return compareString == null;
}
if (compareString == null)
{
return false;
}
int len = theStringBuilder.Length;
if (len != compareString.Length)
{
return false;
}
for (int loop = 0; loop < len; loop++)
{
if (theStringBuilder[loop] != compareString[loop])
{
return false;
}
}
return true;
}
/// <summary>
/// Compares one string to part of another string.
/// </summary>
/// <param name="haystack"></param>
/// <param name="needle">Needle to look for</param>
/// <param name="position">Looks to see if the needle is at position in haystack</param>
/// <returns>Substring(theStringBuilder,offset,compareString.Length) == compareString</returns>
public static bool IsStringAt(this StringBuilder haystack, string needle,int position)
{
if (haystack == null)
{
return needle == null;
}
if (needle == null)
{
return false;
}
int len = haystack.Length;
int compareLen = needle.Length;
if (len < compareLen + position)
{
return false;
}
for (int loop = 0; loop < compareLen; loop++)
{
if (haystack[loop+position] != needle[loop])
{
return false;
}
}
return true;
}
}
}
IMHO you don't have to use StringBuilder in this case... StringBuilder is more useful when used in a loop. Like Microsoft say in In this article
The String object is immutable. Every
time you use one of the methods in the
System.String class, you create a new
string object in memory, which
requires a new allocation of space for
that new object. In situations where
you need to perform repeated
modifications to a string, the
overhead associated with creating a
new String object can be costly. The
System.Text.StringBuilder class can be
used when you want to modify a string
without creating a new object. For
example, using the StringBuilder class
can boost performance when
concatenating many strings together in
a loop
So simply you can use String and avoid use ToString()...

Categories

Resources