TextBox.Text wont show the desired output - c#

I got a project for making an Caesar Cipher. I am stuck in textBox2.text i.e it is not showing the encrypted text.
Kindly check my code and guide , I would be very much thank full!
Please do tell me if there are other mistakes in my code , that would be very nice.
{
key = int.Parse(textBox3.Text) - 48;
// Input.ToLower();
int size = Input.Length;
char[] value = new char[size];
char[] cipher = new char[size];
for (int i = 0; i < size; i++)
{
value[i] = Convert.ToChar(Input.Substring(i, 1));
}
for (int re = 0; re < size; re++)
{
int count = 0;
int a = Convert.ToInt32(value[re]);
for (int y = 1; y <= key; y++)
{
if (count == 0)
{
if (a == 90)
{ a = 64; }
else if (a == 122)
{ a = 96; }
cipher[re] = Convert.ToChar(a + y);
count++;
}
else
{
int b = Convert.ToInt32(cipher[re]);
if (b == 90)
{ b = 64; }
else if (b == 122)
{ b = 96; }
cipher[re] = Convert.ToChar(b + 1);
}
}
}
string ciphertext = "";
for (int p = 0; p < size; p++)
{
ciphertext = ciphertext + cipher[p].ToString();
}
ciphertext.ToUpper();
textBox2.Text = ciphertext;
}

This is very suspicious:
key = int.Parse(textBox3.Text) - 48;
The 48 is a magic number with no explanation. Presumably you're using it because it is the ASCII code for '0'. But int.Parse does not return an ASCII code.
You can either use (only) int.Parse, or else get the ASCII code of the first character in the textbox and do arithmetic on character codes. But combining these is incorrect.
key = int.Parse(textBox3.Text);
or
key = textBox3[0] - '0';
Because your current code is setting key to a negative number, the inner for( y = 1; y <= key; y++ ) loop exits immediately (zero iterations).

Related

Cross Search generate char Matrix

I am trying to create a word search puzzle matrix, this is the code I have,
static void PlaceWords(List<string> words)
{
Random rn = new Random();
foreach (string p in words)
{
String s = p.Trim();
bool placed = false;
while (placed == false)
{
int nRow = rn.Next(0,10);
int nCol = rn.Next(0,10);
int nDirX = 0;
int nDirY = 0;
while (nDirX == 0 && nDirY == 0)
{
nDirX = rn.Next(3) - 1;
nDirY = rn.Next(3) - 1;
}
placed = PlaceWord(s.ToUpper(), nRow, nCol, nDirX, nDirY);
}
}
}
static bool PlaceWord(string s, int nRow, int nCol, int nDirX, int nDirY)
{
bool placed = false;
int LetterNb = s.Length;
int I = nRow;
int J = nCol;
if (MatriceIndice[nRow, nCol] == 0)
{
placed = true;
for (int i = 0; i < s.Length-1; i++)
{
I += nDirX;
J += nDirY;
if (I < 10 && I>0 && J < 10 && J>0)
{
if (MatriceIndice[I, J] == 0)
placed = placed && true;
else
placed = placed && false;
}
else
{
return false;
}
}
}
else
{
return false;
}
if(placed==true)
{
int placeI = nRow;
int placeJ = nCol;
for (int i = 0; i < s.Length - 1; i++)
{
placeI += nDirX;
placeJ += nDirY;
MatriceIndice[placeI,placeJ] = 1;
MatriceChars[placeJ, placeJ] = s[i];
}
}
return placed;
}
However it seems like it is an infinite loop. I am trying to add the code in a 1010 char matrix linked to a 1010 int matrix initially filled with 0 where I change the cases to 1 if the word is added to the matrix. How should I fix the code?
There are several errors. First,
MatriceChars[placeJ, placeJ] = s[i];
should be
MatriceChars[placeI, placeJ] = s[i];
Second,
for (int i = 0; i < s.Length - 1; i++)
(two occurrences) should be
for (int i = 0; i < s.Length; i++)
(You do want all the letters in the words, right?)
Third, when testing indices, you should use I >= 0, not I > 0, as the matrix indices start at 0.
However, the main logic of the code seems to work, but if you try to place too many words, you will indeed enter an infinite loop, since it just keeps trying and failing to place words that can never fit.

SQF to C# - Encryption code convertion

G'Day. I am attempting to convert a function that was initially made for Bohemia Interactives language SQF to C#. The script is designed to encrypt a string with the encryption method RC4, however, it works a little bit different to the way this is traditionally done thanks to limitations of the arma3 engine. The whole idea of this is so I can encrypt a string with the C# program, and decrypt it through Arma 3 in-game.
Here is the code I am trying to convert from.
/*
Function: ALiVE_fnc_crypt
Author(s): Naught
Version: 1.0
Description:
Encrypts or decrypts a string with a specified encryption key.
Parameters:
0 - Decrypt (0) or encrypt (1) [number]
1 - Encryption method name [string]
2 - Encrypted or plain data [string]
3 - Encryption key [string]
Returns:
Encrypted or decrypted data or nothing on failure [string:nil]
Note(s):
1. Current encryption method names:
- "rc4" // Rivest Cipher 4 Stream Encryption Algorithm
*/
// Constants
MAX_CHAR_SIZE = 8;
CHAR_ZERO_REP = 256;
private ["_method", "_key"];
_encText = _this select 0;
_key = _this select 1;
private ["_fnc_intToBin"];
_fnc_intToBin = {
private ["_int", "_bin", "_pwr", "_bool"];
_int = _this select 0;
_bin = if ((count _this) > 1) then {_this select 1} else {[]};
for "_i" from (MAX_CHAR_SIZE - 1) to 0 step (-1) do
{
_pwr = 2^(_i);
_bool = _pwr <= _int;
_bin set [(count _bin), _bool];
if (_bool) then {_int = _int - _pwr};
};
_bin
};
private ["_bin"];
_bin = [];
// Convert string to UTF-8 binary
{ // count (faster than forEach)
[(if (_x == CHAR_ZERO_REP) then {0} else {_x}), _bin] call _fnc_intToBin;
false;
} count toArray(_encText);
systemChat str _bin;
// Encrypt & decrypt methods
_key = toArray(_key);
private ["_keyLen", "_state", "_temp", "_j"];
_keyLen = count _key;
_state = [];
_temp = 0;
_j = 0;
// Key-Scheduling Algorithm
for "_i" from 0 to 255 do {_state set [_i,_i]};
for "_i" from 0 to 255 do
{
_temp = _state select _i;
_j = (_j + _temp + (_key select (_i mod _keyLen))) mod 256;
_state set [_i, (_state select _j)];
_state set [_j, _temp];
};
private ["_temp1", "_temp2", "_rand", "_i", "_mod", "_rbit"];
_temp1 = 0;
_temp2 = 0;
_rand = [];
_i = 0;
_j = 0;
hint str _bin;
// Pseudo-Random Generation Algorithm
{
_mod = _forEachIndex % MAX_CHAR_SIZE;
if (_mod == 0) then
{
_i = (_i + 1) mod 256;
_j = (_j + (_state select _i)) mod 256;
_temp1 = _state select _i;
_temp2 = _state select _j;
_state set [_i, _temp2];
_state set [_j, _temp1];
_rand = [(_state select ((_temp1 + _temp2) mod 256))] call _fnc_intToBin;
};
_rbit = _rand select _mod;
_bin set [_forEachIndex, (_x && !_rbit) || {!_x && _rbit}]; // XOR
} forEach _bin;
private ["_dec", "_buf", "_mod"];
_dec = 0;
_buf = [];
// Convert binary array to UTF-8 string
{
_mod = _forEachIndex % MAX_CHAR_SIZE;
if (_x) then {_dec = _dec + 2^((MAX_CHAR_SIZE - 1) - _mod)};
if (_mod == 7) then
{
if (_dec == 0) then {_dec = CHAR_ZERO_REP};
_buf set [(count _buf), _dec];
_dec = 0;
};
} forEach _bin;
toString(_buf)
I have made slight adjustments to this code, and it all still works fine in Arma 3.
Now, the converted function. I have changed about everything in this code from what my initial code was to try and get it working, so at this point, it may be completely incorrect, however, I will include it anyway.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace encrypt
{
class Program
{
static public int MAX_CHAR_SIZE = 8;
static public int CHAR_ZERO_REP = 256;
static public int _keyLen;
static void Main()
{
string[] args = new string[2];
args[0] = "Some Random Code";
args[1] = "4tuIc9tai";
string text = args[0];
// Convert the text to an array of decimal unicode || Same as toArray in arma 3
string[] txtArray = new string[text.Length];
txtArray = text.ToCharArray().Select(c => c.ToString()).ToArray();
int[] utf = getUni(txtArray);
// Convert the key to an array of decimal unicode || Same as toArray in arma 3
string[] keyArray = new string[args[1].Length];
keyArray = args[1].ToCharArray().Select(c => c.ToString()).ToArray();
int[] key = getUni(keyArray);
// Debug the output
//foreach (int i in utf){Console.Write(i); Console.Write(",");} Console.WriteLine();foreach (int i in key){Console.Write(i);Console.Write(","); }
// Convert string to UTF-8 binary
Dictionary<int, bool> _bin = new Dictionary<int, bool>();
foreach (int i in utf)
{
int _num;
if (i == CHAR_ZERO_REP)
{
_num = 0;
}
else
{
_num = i;
}
_bin = intToBin(_num, _bin);
}
foreach (KeyValuePair<int, bool> i in _bin)
{
Console.Write(Convert.ToString(i.Value));
Console.Write(", ");
}
// Encrypt & decrypt methods
_keyLen = key.Length;
int[] _state = new int[1024];
int _temp = 0;
int _j = 0;
// Key-Scheduling Algorithm
for (int _i = 0; _i < 255; _i++)
{
_state.SetValue(_i, _i);
}
for (int _i = 0; _i < 255; _i++)
{
_temp = _state[_i];
_j = (_j + _temp + key[_i % _keyLen]) % 256;
_state.SetValue(_i, _state[_j]);
_state.SetValue(_j, _temp);
}
// Pseudo-Random Generation Algorithm
int _temp1 = 0;
int _temp2 = 0;
Dictionary<int, bool> _rand = new Dictionary<int, bool>();
int __i = 0;
int __j = 0;
int indx = 0;
for (int i = 0; i < _bin.Count-1; i++)
{
int _mod = indx % MAX_CHAR_SIZE;
if (_mod == 0)
{
__i = (__i + 1) % 256;
__j = (__j + _state[__i]) % 256;
_temp1 = _state[__i];
_temp2 = _state[__j];
_state.SetValue(__i, _temp2);
_state.SetValue(__j, _temp1);
_rand = intToBin(_state[_temp1 + _temp2] % 256, _rand);
}
bool _rbit = _rand[_mod];
bool _bit = _bin[i];
if (_bin.ContainsKey(indx))
{
_bin.Remove(indx);
}
_bin.Add(indx, (_bit && !_rbit) || (!_bit && _rbit));
indx++;
}
// Convert binary array to UTF-8 string
int _dec = 0;
int[] _buf = new int[_bin.Count];
for (int i = 0; i < _bin.Count-1; i++)
{
int _mod = i % MAX_CHAR_SIZE;
Console.WriteLine(i);
if (_bin[i])
{
_dec = _dec + 2 ^ ((MAX_CHAR_SIZE - 1) - _mod);
}
if (_mod == 7)
{
if (_dec == 0)
{
_dec = CHAR_ZERO_REP;
}
_buf.SetValue(_dec, _buf.Length-1);
_dec = 0;
}
_buf.SetValue(_dec, _buf.Length - 1);
}
Console.ReadLine();
}
static int[] getUni(string[] txtArray)
{
int[] ret = new int[txtArray.Length];
int idx = 0;
foreach (string i in txtArray)
{
ret.SetValue(Encoding.UTF8.GetBytes(i)[0], idx);
idx++;
}
return ret;
}
static Dictionary<int, bool> intToBin(int val, Dictionary<int, bool> bin)
{
for (int i = MAX_CHAR_SIZE-1; i > 0; i--)
{
int _pwr = 2 ^ i;
bool _bool = _pwr <= val;
int cc = bin.Count;
if (bin.ContainsKey(cc))
{
bin.Remove(cc);
}
bin.Add(cc, _bool);
if (_bool)
{
val = val - _pwr;
}
}
return bin;
}
}
}
Any help what so ever would be great :)

Listbox not removing values in c# GUI

The user basically enters a number of hex values into a textbox separated by commas eg. AA,1B,FF. These are then displayed in a listbox box. if the number of hex values in the textbox exceeds the size to transfer defined by the user, the listbox only displays the this number of values or if the size to transfer is bigger that adds zero values to the listbox.
this works fine until you enter a value with a zero in front of it such as AA,BB,CC,DD,EE,0F, if sizeToTransfer = 2, the listbox should display 0xAA and 0xBB. but instead it only removes the 0F value?
I'm pretty new to programming so it may be something obvious I'm missing any help would be appreciated.
private void WriteSPI1_Click(object sender, EventArgs e)
{
string hexstring = textbox1.Text;
HexValues.Items.Clear();
string[] hexarray = hexstring.Split((",\r\n".ToCharArray()), StringSplitOptions.RemoveEmptyEntries);
byte[] hexbytes = new byte[hexarray.Length];
uint num = Convert.ToUInt32(hexarray.Length);
for (int j = 0; j < hexarray.Length; j++)
{
hexbytes[j] = Convert.ToByte(hexarray[j], 16);
Hexlist.Add(hexbytes[j]);
writebuff = Hexlist.ToArray();
x = writebuff[j].ToString("X2");
HexValues.Items.Add("0x" + x);
}
if (hexarray.Length > sizeToTransfer)
{
diff = num - sizeToTransfer;
for (i = 0; i < diff+1; i++)
{
HexValues.Items.Remove("0x" + x);
}
}
else
{
diff = sizeToTransfer - num;
for (i = 0; i < diff; i++)
{
HexValues.Items.Add("0x00");
}
}
}
CHANGE
for (int j = 0; j < sizeToTransfer; j++)
{
hexbytes[j] = Convert.ToByte(hexarray[j], 16);
Hexlist.Add(hexbytes[j]);
writebuff = Hexlist.ToArray();
x = writebuff[j].ToString("X2");
HexValues.Items.Add("0x" + x);
}
WITH
for (int j = 0; j < hexarray.Length; j++)
{
hexbytes[j] = Convert.ToByte(hexarray[j], 16);
Hexlist.Add(hexbytes[j]);
writebuff = Hexlist.ToArray();
x = writebuff[j].ToString("X2");
HexValues.Items.Add("0x" + x);
}
and remove the if stantment that follow

C# Google Static Maps encoded path calculation

I'm writing a tool that gets GPS coordinates from a XML file and sends them to the Google Static Maps API. I'm trying to get a polyline from Google.
I've found the documentation and so far I've written this to convert a double value to a encoded value for a polyline:
private String convertDouble(Double _input)
{
String result = String.Empty;
//value * 1e5
Int32 multiplication = Convert.ToInt32(Math.Floor(_input * 1e5));
//value to binary string
String binaryString = Convert.ToString(multiplication, 2);
//binary to hex
binaryString = BinaryStringToHexString(binaryString);
//value to hex + 1
Int32 hexConvert = Convert.ToInt32(binaryString, 16) + Convert.ToInt32("01", 16);
//value to binary string
binaryString = Convert.ToString(hexConvert, 2);
//binary string zu int[] for further calculations
Int32[] bitValues = new Int32[binaryString.Length];
for (Int32 i = 0; i < bitValues.Length; i++)
{
if (binaryString[i] == '0')
{
bitValues[i] = 0;
}
else
{
bitValues[i] = 1;
}
}
//shift binary to left
Int32[] bitValues_2 = new Int32[bitValues.Length];
for (Int32 i = 0; i < bitValues.Length - 1; i++)
{
bitValues_2[i] = bitValues[i + 1];
}
bitValues_2[bitValues_2.Length - 1] = 0;
//if input value is negative invert binary
if (_input < 0)
{
for (Int32 i = 0; i < bitValues.Length; i++)
{
if (bitValues_2[i] == 0)
{
bitValues_2[i] = 1;
}
else
{
bitValues_2[i] = 0;
}
}
}
//make blocks of 5
Int32 lengthDifference = bitValues_2.Length % 5;
Int32[] bitValues_3 = new Int32[bitValues_2.Length - lengthDifference];
for (Int32 i = bitValues_2.Length - 1; i > (bitValues_2.Length - bitValues_3.Length); i--)
{
bitValues_3[i - (bitValues_2.Length - bitValues_3.Length)] = bitValues_2[i];
}
//twist blocks
Int32[] bitValues_4 = new Int32[bitValues_3.Length];
Int32 numberOfBlocks = bitValues_3.Length / 5;
Int32 counter = 0;
String[] stringValues = new String[numberOfBlocks];
for (Int32 i = numberOfBlocks - 1; i >= 0; i--)
{
for (Int32 j = i * 5; j < (i * 5) + 5; j++)
{
bitValues_4[counter] = bitValues_3[j];
counter++;
}
}
counter = 0;
//write int[] into strings for final conversion
for (Int32 i = 0; i < bitValues_4.Length; i++)
{
if (i > 0 && i % 5 == 0)
{
counter++;
}
stringValues[counter] += bitValues_4[i].ToString();
}
// blocks ^ 0x20 (32) and convert to char
Int32 value = 0;
Int32[] intValues = new Int32[stringValues.Length];
Char[] charValues = new Char[stringValues.Length];
for (Int32 i = 0; i < stringValues.Length; i++)
{
value = Convert.ToInt32(stringValues[i], 2);
if (i < stringValues.Length - 1)
{
intValues[i] = value ^ 32;
}
else
{
intValues[i] = value;
}
intValues[i] = intValues[i] + 63;
charValues[i] = (Char)intValues[i];
result += charValues[i];
}
return result;
}
If I use the value from the documentation
-179.9832104
I get the result
`~oia#
Which is fine, but if I use one of my values e.g.:
LAT: 8.7587061 LONG: 48.6331662
LAT: 8.8905152 LONG: 48.6226701
I get the wrong values. The final polyline should be in southern Germany. But with my calculation the polyline is somewhere near a cost. Maybe there is a finished class that gives me the encoded coordinates and I haven't found it yet.
And yes, I have to encode the polylines, because there will be many different coordinates in the XML (the GPS tracker runs for several hours and captures the location every 10 seconds).
Well, after another night of searching and testing I have found a solution.
Brian Pedersen has a solution in his blog. And it works just like it should.
I don't want to copy and paste the code here, but the link has it.

how can i find lcs length between two large strings

I've written the following code in C# for obtaining the length of longest common subsequence of two texts given by use, but it doesn't work with large strings. Could you please help me. I'm really confused.
public Form1()
{
InitializeComponent();
}
public int lcs(char[] s1, char[] s2, int s1size, int s2size)
{
if (s1size == 0 || s2size == 0)
{
return 0;
}
else
{
if (s1[s1size - 1] == s2[s2size - 1])
{
return (lcs(s1, s2, s1size - 1, s2size - 1) + 1);
}
else
{
int x = lcs(s1, s2, s1size, s2size - 1);
int y = lcs(s1, s2, s1size - 1, s2size);
if (x > y)
{
return x;
}
else
return y;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
string st1 = textBox2.Text.Trim(' ');
string st2 = textBox3.Text.Trim(' ');
char[] a = st1.ToCharArray();
char[] b = st2.ToCharArray();
int s1 = a.Length;
int s2 = b.Length;
textBox1.Text = lcs(a, b, s1, s2).ToString();
}
Here you are using the Recursion method. So it leads the program to occur performance problems as you mentioned.
Instead of recursion, use the dynamic programming approach.
Here is the C# Code.
public static void LCS(char[] str1, char[] str2)
{
int[,] l = new int[str1.Length, str2.Length];
int lcs = -1;
string substr = string.Empty;
int end = -1;
for (int i = 0; i < str1.Length; i++)
{
for (int j = 0; j < str2.Length; j++)
{
if (str1[i] == str2[j])
{
if (i == 0 || j == 0)
{
l[i, j] = 1;
}
else
l[i, j] = l[i - 1, j - 1] + 1;
if (l[i, j] > lcs)
{
lcs = l[i, j];
end = i;
}
}
else
l[i, j] = 0;
}
}
for (int i = end - lcs + 1; i <= end; i++)
{
substr += str1[i];
}
Console.WriteLine("Longest Common SubString Length = {0}, Longest Common Substring = {1}", lcs, substr);
}
Here is a solution how to find the longest common substring in C#:
public static string GetLongestCommonSubstring(params string[] strings)
{
var commonSubstrings = new HashSet<string>(strings[0].GetSubstrings());
foreach (string str in strings.Skip(1))
{
commonSubstrings.IntersectWith(str.GetSubstrings());
if (commonSubstrings.Count == 0)
return string.Empty;
}
return commonSubstrings.OrderByDescending(s => s.Length).DefaultIfEmpty(string.Empty).First();
}
private static IEnumerable<string> GetSubstrings(this string str)
{
for (int c = 0; c < str.Length - 1; c++)
{
for (int cc = 1; c + cc <= str.Length; cc++)
{
yield return str.Substring(c, cc);
}
}
}
I found it here: http://www.snippetsource.net/Snippet/75/longest-common-substring
Just for fun, here is one example using Queue<T>:
string LongestCommonSubstring(params string[] strings)
{
return LongestCommonSubstring(strings[0], new Queue<string>(strings.Skip(1)));
}
string LongestCommonSubstring(string x, Queue<string> strings)
{
if (!strings.TryDequeue(out var y))
{
return x;
}
var output = string.Empty;
for (int i = 0; i < x.Length; i++)
{
for (int j = x.Length - i; j > -1; j--)
{
string common = x.Substring(i, j);
if (y.IndexOf(common) > -1 && common.Length > output.Length) output = common;
}
}
return LongestCommonSubstring(output, strings);
}
It's still using recursion though, but it's a nice example of Queue<T>.
I refactored the C++ code from Ashutosh Singh at https://iq.opengenus.org/longest-common-substring-using-rolling-hash/ to create a rolling hash approach in C# - this will find the substring in O(N * log(N)^2) time and O(N) space
using System;
using System.Collections.Generic;
public class RollingHash
{
private class RollingHashPowers
{
// _mod = prime modulus of polynomial hashing
// any prime number over a billion should suffice
internal const int _mod = (int)1e9 + 123;
// _hashBase = base (point of hashing)
// this should be a prime number larger than the number of characters used
// in my use case I am only interested in ASCII (256) characters
// for strings in languages using non-latin characters, this should be much larger
internal const long _hashBase = 257;
// _pow1 = powers of base modulo mod
internal readonly List<int> _pow1 = new List<int> { 1 };
// _pow2 = powers of base modulo 2^64
internal readonly List<long> _pow2 = new List<long> { 1L };
internal void EnsureLength(int length)
{
if (_pow1.Capacity < length)
{
_pow1.Capacity = _pow2.Capacity = length;
}
for (int currentIndx = _pow1.Count - 1; currentIndx < length; ++currentIndx)
{
_pow1.Add((int)(_pow1[currentIndx] * _hashBase % _mod));
_pow2.Add(_pow2[currentIndx] * _hashBase);
}
}
}
private class RollingHashedString
{
readonly RollingHashPowers _pows;
readonly int[] _pref1; // Hash on prefix modulo mod
readonly long[] _pref2; // Hash on prefix modulo 2^64
// Constructor from string:
internal RollingHashedString(RollingHashPowers pows, string s, bool caseInsensitive = false)
{
_pows = pows;
_pref1 = new int[s.Length + 1];
_pref2 = new long[s.Length + 1];
const long capAVal = 'A';
const long capZVal = 'Z';
const long aADif = 'a' - 'A';
unsafe
{
fixed (char* c = s)
{
// Fill arrays with polynomial hashes on prefix
for (int i = 0; i < s.Length; ++i)
{
long v = c[i];
if (caseInsensitive && capAVal <= v && v <= capZVal)
{
v += aADif;
}
_pref1[i + 1] = (int)((_pref1[i] + v * _pows._pow1[i]) % RollingHashPowers._mod);
_pref2[i + 1] = _pref2[i] + v * _pows._pow2[i];
}
}
}
}
// Rollingnomial hash of subsequence [pos, pos+len)
// If mxPow != 0, value automatically multiply on base in needed power.
// Finally base ^ mxPow
internal Tuple<int, long> Apply(int pos, int len, int mxPow = 0)
{
int hash1 = _pref1[pos + len] - _pref1[pos];
long hash2 = _pref2[pos + len] - _pref2[pos];
if (hash1 < 0)
{
hash1 += RollingHashPowers._mod;
}
if (mxPow != 0)
{
hash1 = (int)((long)hash1 * _pows._pow1[mxPow - (pos + len - 1)] % RollingHashPowers._mod);
hash2 *= _pows._pow2[mxPow - (pos + len - 1)];
}
return Tuple.Create(hash1, hash2);
}
}
private readonly RollingHashPowers _rhp;
public RollingHash(int longestLength = 0)
{
_rhp = new RollingHashPowers();
if (longestLength > 0)
{
_rhp.EnsureLength(longestLength);
}
}
public string FindCommonSubstring(string a, string b, bool caseInsensitive = false)
{
// Calculate max neede power of base:
int mxPow = Math.Max(a.Length, b.Length);
_rhp.EnsureLength(mxPow);
// Create hashing objects from strings:
RollingHashedString hash_a = new RollingHashedString(_rhp, a, caseInsensitive);
RollingHashedString hash_b = new RollingHashedString(_rhp, b, caseInsensitive);
// Binary search by length of same subsequence:
int pos = -1;
int low = 0;
int minLen = Math.Min(a.Length, b.Length);
int high = minLen + 1;
var tupleCompare = Comparer<Tuple<int, long>>.Default;
while (high - low > 1)
{
int mid = (low + high) / 2;
List<Tuple<int, long>> hashes = new List<Tuple<int, long>>(a.Length - mid + 1);
for (int i = 0; i + mid <= a.Length; ++i)
{
hashes.Add(hash_a.Apply(i, mid, mxPow));
}
hashes.Sort(tupleCompare);
int p = -1;
for (int i = 0; i + mid <= b.Length; ++i)
{
if (hashes.BinarySearch(hash_b.Apply(i, mid, mxPow), tupleCompare) >= 0)
{
p = i;
break;
}
}
if (p >= 0)
{
low = mid;
pos = p;
}
else
{
high = mid;
}
}
// Output answer:
return pos >= 0
? b.Substring(pos, low)
: string.Empty;
}
}

Categories