Checking the values of a long string from a specific point - c#

This is a follow on from my last question.
The string I am trying to compare comes through as follows:
Discovered Peripherial: <CBPeripheral: 0x39b8b50 identifier = DEEE65FB-FF1F-A6A9-4C3C-5784F41B0D39, Name = "rawr", state = connecting>
What I'm trying to do is check the identifier number to that which I'm storing in my program. To do that, I have done the following:
private void AppendString(string message)
{
message.Substring(message.Length-77, message.Length);
outputContent.text += "\n" + message;
}
The \n is in there because I'm reading in 6 different devices and they all generate the above line. So I needed something to make it easier to read.
Then in my update function I am checking to see if they are similar like so:
if(String.Equals(myValues["UUID"], outputContent.text, StringComparison.OrdinalIgnoreCase))
{
Instantiate(model1, new Vector3(-2.5f, 3.0f,0), Quaternion.identity);
}
However when I run this on my iPad, xCode generates the following message:
ArgumentOutOfRangeException: startIndex + length > this.length
Parameter name: length
Which I'm guessing means I have miscounted the amount of characters I need to count back from in the substring.
My question is this:
Is there a better way in which I can compare my stored value with that of a specific part of a really long string or have I done something silly in my code which is generating that error?
This is a Unity project which I'm building onto an iPad and makes use of some functionality I can't replicate on a mac.

in your code i observed that you are calling Substring() method but not getting/saving its result into some variable .
message.Substring(message.Length-77, message.Length);
as string is an immutable which can not be modified.
hence when you call the Substring() method it cuts the required text and returns, which you have to save it on some variable to proceed further.
as below:
replace your function AppendString() as below :
private void AppendString(string message)
{
message= message.Substring(message.Length-77, message.Length);
outputContent.text += "\n" + message;
}

Related

Delete Message When Detects A Certain Word

I am pretty new to making discord bots and have tried to make a filter to when my bot detects a certain word in a message it will delete it. It is throwing no errors, it just will not delete the message. I might just have the code in the wrong spot, but I do not know. If anyone can help me out, I'd appreciate it.
private async Task BadWordsWarn(SocketMessage message)
{
string[] badWords = File.ReadAllLines(Environment.CurrentDirectory + "/wordstodelete.txt");
if (badWords.Any(message.Content.Contains))
await message.DeleteAsync();
}
How are you calling BadWordsWarn? I suspect that you perhaps are not awaiting the async call, or badWords isn't actually being populated for the version of code you're running e.g. is the file being copied to the output directory if you're running the release version?
The C# code works - not optimal as the badWords array should be passed in as opposed to being read every time but there's nothing wrong with the syntax.
Perhaps the Discord message contents is in JSON and needs to be parsed?
If it's a string, this code is case-insensitive & definitely works.
var badWords = new [] {
"grape",
"apple"
};
var messageContent = "good good good grape";
foreach(var word in badWords) {
var contentHasBadWord = messageContent.IndexOf(word, StringComparison.OrdinalIgnoreCase) >= 0;
if (contentHasBadWord) {
Console.WriteLine("Bad word found - " + word);
// delete message
break;
}
}
dotnetfiddle

C#: System.Windows.Forms.SendKeys.SendWait does not work with the path as input

Here is my code
private string path = Path.GetTempPath() + "Test.pdf";
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.AllThreads;
System.Windows.Forms.SendKeys.SendWait(path);
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.UIThreadOnly;
Keyboard.SendKeys("{Enter}");
There is a window explorer for opening a file. The file exists on the temp path. It sometimes works and sometimes it enter the path as :\Users\.... which means it ignores C. I am not sure what is the problem? Why it is inconsistent? Any help is appreciated.
I already tried
private string path = #"" + Path.GetTempPath() + "Test.pdf";
but it is the same (sometimes works, sometimes does not)
I added empty char before the path
private string path = #" " + Path.GetTempPath() + "Test.pdf";
But still it is the same!
I had a similar problem with Coded UI but it omitted a small number of characters randomly throughout the string. I never found out the real reason, but I got around the problem by sending the characters one at a time with a short pause between them. I use code similar to the following:
void SendKeysSlowly(string text)
{
foreach ( char s in text )
{
SendKeys(s); // Choose the appropriate send routine
System.Threading.Thread.Sleep(50); // Milliseconds, adjust as needed
}
}
Also, you should ensure the string always starts with a "C:"? You could add code of the form Assert(path.StartsWith("C:\\")); before the first ...Sendkeys call.
Try using
Path.Combine(Path.GetTempPath(), "Test.pdf")

Search String takes a long time the first time only?

No shortage of search for string performance questions out there yet I still can not make heads or tails out of what the best approach is.
Long story short, I have committed to moving from 4NT to PowerShell. In leaving the 4NT I am going to miss the console super quick string searching utility that came with it called FFIND. I have decided to use my rudimentary C# programming skills to try an create my own utility to use in PowerShell that is just as quick.
So far search results on a string search in 100's of directories across a few 1000 files, some of which are quite large, are FFIND 2.4 seconds and my utility 4.4 seconds..... after I have ran mine at least once????
The first time I run them FFIND does it near the same time but mine takes over a minute? What is this? Loading of libraries? File indexing? Am I doing something wrong in my code? I do not mind waiting a little longer but the difference is extreme enough that if there is a better language or approach I would rather start down that path now before I get too invested.
Do I need to pick another language to write a string search that will be lighting fast
I have the need to use this utility to search through 1000 of files for strings in web code, C# code, and another propitiatory language that uses text files. I also need to be able to use this utility to find strings in very large log files, MB size.
class Program
{
public static int linecounter;
public static int filecounter;
static void Main(string[] args)
{
//
//INIT
//
filecounter = 0;
linecounter = 0;
string word;
// Read properties from application settings.
string filelocation = Properties.Settings.Default.FavOne;
// Set Args from console.
word = args[0];
//
//Recursive search for sub folders and files
//
string startDIR;
string filename;
startDIR = Environment.CurrentDirectory;
//startDIR = "c:\\SearchStringTestDIR\\";
filename = args[1];
DirSearch(startDIR, word, filename);
Console.WriteLine(filecounter + " " + "Files found");
Console.WriteLine(linecounter + " " + "Lines found");
Console.ReadKey();
}
static void DirSearch(string dir, string word, string filename)
{
string fileline;
string ColorOne = Properties.Settings.Default.ColorOne;
string ColorTwo = Properties.Settings.Default.ColorTwo;
ConsoleColor valuecolorone = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorOne);
ConsoleColor valuecolortwo = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorTwo);
try
{
foreach (string f in Directory.GetFiles(dir, filename))
{
StreamReader file = new StreamReader(f);
bool t = true;
int counter = 1;
while ((fileline = file.ReadLine()) != null)
{
if (fileline.Contains(word))
{
if (t)
{
t = false;
filecounter++;
Console.ForegroundColor = valuecolorone;
Console.WriteLine(" ");
Console.WriteLine(f);
Console.ForegroundColor = valuecolortwo;
}
linecounter++;
Console.WriteLine(counter.ToString() + ". " + fileline);
}
counter++;
}
file.Close();
file = null;
}
foreach (string d in Directory.GetDirectories(dir))
{
//Console.WriteLine(d);
DirSearch(d,word,filename);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If you want to speed up your code run a performance analysis and see what is taking the most time. I can almost guaruntee the longest step here will be
fileline.Contains(word)
This function is called on every line of the file, on every file. Naively searching for a word in a string can taken len(string) * len(word) comparisons.
You could code your own Contains method, that uses a faster string comparison algorithm. Google for "fast string exact matching". You could try using a regex and seeing if that gives you a performance enhancement. But I think the simplest optimization you can try is :
Don't read every line. Make a large string of all the content of the file.
StreamReader streamReader = new StreamReader(filePath, Encoding.UTF8);
string text = streamReader.ReadToEnd();
Run contains on this.
If you need all the matches in a file, then you need to use something like Regex.Matches(string,string).
After you have used regex to get all the matches for a single file, you can iterate over this match collection (if there are any matches). For each match, you can recover the line of the original file by writing a function that reads forward and backward from the match object index attribute, to where you find the '\n' character. Then output that string between those two newlines, to get your line.
This will be much faster, I guarantee it.
If you want to go even further, some things I've noticed are :
Remove the try catch statement from outside the loop. Only use it exactly where you need it. I would not use it at all.
Also make sure your system is running, ngen. Most setups usually have this, but sometimes ngen is not running. You can see the process in process explorer. Ngen generates a native image of the C# managed bytecode so the code does not have to be interpreted each time, but can be run natively. This speeds up C# a lot.
EDIT
Other points:
Why is there a difference between first and subsequent run times? Seems like caching. The OS could have cached the requests for the directories, for the files, for running and loading programs. Usually one sees speedups after a first run. Ngen could also be playing a part here, too, in generating the native image after compilation on the first run, then storing that in the native image cache.
In general, I find C# performance too variable for my liking. If the optimizations suggested are not satisfactory and you want more consistent performance results, try another language -- one that is not 'managed'. C is probably the best for your needs.

Writing to the console from a method .NET 4.0

The following is a short clock program from the book "programming in the key of c#". I'm not familiar with the Timers library at all so some of this syntax I don't really get. What I want to understand and I don't is the line Console.Write(str) in the method in this little program. How does Main know what to print to the console? Is it the empty Console.WriteLine() call that makes the time print out every second? When I'm reading about these concepts it seems easy after the fact to understand what's going on. Based on what I've asked, what are the things about C# that I don't really understand yet?
using System;
using System.Timers; // Requires System.dll
class Clock
{
static int iStringLength;
static void Main()
{
Console.WriteLine("Press Enter to end program");
Console.WriteLine();
Timer tmr = new Timer();
tmr.Elapsed += new ElapsedEventHandler(TimerHandler);
tmr.Interval = 1000;
tmr.Start();
Console.ReadLine();
tmr.Stop();
}
static void TimerHandler(object obj, ElapsedEventArgs eea)
{
Console.Write(new String('\b', iStringLength));
string str = String.Format("{0} {1} ",
eea.SignalTime.ToLongDateString(),
eea.SignalTime.ToLongTimeString());
iStringLength = str.Length;
Console.Write(str);
}
}
Main() doesn't print anything to the console, except for the initial blank line.
Console.Write() in the TimerHandler() callback runs every second and prints the time.
str contains the value of the string after the String.Format() function is called. That function is documented here: http://msdn.microsoft.com/en-us/library/b1csw23d.aspx
In your code, the {0} is replaced by the formatted representation of eea.SignalTime.ToLongDateString(), and the {1} is replaced by a formatted representation of eea.SignalTime.ToLongTimeString().
So to answer
What I want to understand and I don't is the line Console.Write(str)
in the method in this little program. How does Main know what to print
to the console?
the answer is "It writes whatever the String.Format() function has determined the value of "str" is in this line:"
string str = String.Format("{0} {1} ",
eea.SignalTime.ToLongDateString(),
eea.SignalTime.ToLongTimeString());
The WriteLine() function just prints an empty line and really has nothing to do with the string that shows the date/time as you asked.
For the record, Console.Write and Console.Writeline are documented here and here, respectively.
Console.WriteLine() without any parameters does exactly what it sounds like, just prints out an empty line (newline).
Writes the current line terminator to the standard output stream.
Console.WriteLine(xxx) with any parameter prints the parameter on a line, followed by a new line.
Writes the specified data, followed by the current line terminator, to
the standard output stream.
In your TimerHandler method, you are using Console.Write(xxx), which just prints the text representation of the parameter, without a newline.
Writes the text representation of the specified object to the standard
output stream.

Do __LINE__ __FILE__ equivalents exist in C#?

For logging purposes
__LINE__
__FILE__
were my friends in C/C++. In Java to get that information I had to throw an exception and catch it. Why are these old standbys so neglected in the modern programming languages? There is something magical about their simplicity.
Caller Information has been added to .NET 4.5. This will be compiled, a big improvement over having to examine the stack trace manually.
public void Log(string message,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
// Do logging
}
Simply call it in this manner. The compiler will fill in the file name and line number for you:
logger.Log("Hello!");
It is uglier, but you can do something like this in C# using the StackTrace and StackFrame classes:
StackTrace st = new StackTrace(new StackFrame(true));
Console.WriteLine(" Stack trace for current level: {0}", st.ToString());
StackFrame sf = st.GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Method: {0}", sf.GetMethod().Name);
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());
Of course, this comes with some overhead.
With Caller Information (introduced in .NET 4.5) you can create the equivalent of __LINE__ and __FILE__ in C#:
static int __LINE__([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}
static string __FILE__([System.Runtime.CompilerServices.CallerFilePath] string fileName = "")
{
return fileName;
}
The only thing to remember is that these are functions and not compiler directives.
So for example:
MessageBox.Show("Line " + __LINE__() + " in " + __FILE__());
If you were to use this in practise then I'd suggest different names. I've used the C/C++ names just to make it clearer what they are returning, and something like CurrentLineNumber() and CurrentFileName() might be better names.
The advantage of using Caller Information over any solution that uses the StackTrace is that the line and file information is available for both debug and release.
The closest thing to those is the fact that you can create a StackTrace object and find out the name of the method at the top of the stack, so you can get close to the functionality of the __FUNCTION__ macro.
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
foreach (StackFrame stackFrame in stackFrames)
Console.WriteLine(stackFrame.GetMethod().Name);
To reduce the cost of typing this out by hand, and also the runtime code, you can write a helper method:
[Conditional("Debug")]
public void LogMethodName()
{
Trace.WriteLine("Entering:" + new StackTrace().GetFrame(1).GetMethod().Name);
}
Note how we get frame 1, as frame 0 would be LogMethodName itself. By marking it as Conditional("Debug") we ensure that the code is removed from release builds, which is one way to avoid the runtime cost where it may not be needed.
Because the stack trace contains most of what you need. It will not give you the name of the file but it will give you the class/method name. It also contains the line number. It is not neglected it is automatic. You just need to throw an exception like you do it in Java
Here's a way to get the line number: http://askville.amazon.com/SimilarQuestions.do?req=line-numbers-stored-stack-trace-C%2523-application-throws-exception
If you use log4net, you can get the line number and file name in your logs, but:
it can decrease your app. performance
you have to have .PDB files together with your assemblies.
There are already some suggestions to achieve what you want. Either use the StackTrace object or better log4net.
In Java to get that information I had to throw an exception and catch it.
That's not quite true. You can have it without throwing exceptions, too. Have a look to log4j. It even logs your method and class name, without polluting your code with hard coded strings containing the current method name (at least I have seen this in some occasions).
Why are these old standbys so neglected in the modern programming languages?
Java and C# don't make use (in the latter: excessive use) of preprocessors. And I think it's good. Abusing preprocessors to make unreadable code is very easy. And if programmers can abuse some technique ... they will abuse it.
Just a note about performance, which is very likely to be the next thing, which pops up in your mind:
If you use StackTrace or log4net you will always will read or hear that it is slow, because it uses Reflection. I am using log4net and I never encountered logging as a performance bottle neck. If it would be, I can declaratively deactivate (parts of) logging -- without changing the source code. That's pure beauty compared to delete all the logging lines in C/C++ code! (Besides: If performance is a primary goal, I would use C/C++ ... it will never die despite of Java and C#.)
Having used the FILE and LINE macros for many years for logging in C/C++ I really wanted a similar solution in C#. This is my solution. I prefer it to #fostandy suggestion of creating many overloads with varying number of parameters. This seems the less intrusive and does not limit the number of formatted parameters. You just have to be willing to accept the addition of the F.L() parameter at start of every Log.Msg() call.
using System;
using System.Runtime.CompilerServices;
namespace LogFileLine
{
public static class F
{
// This method returns the callers filename and line number
public static string L([CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
{
// Remove path leaving only filename
while (file.IndexOf("\\") >= 0)
file = file.Substring(file.IndexOf("\\")+1);
return String.Format("{0} {1}:", file, line);
}
}
public static class Log
{
// Log a formatted message. Filename and line number of location of call
// to Msg method is automatically appended to start of formatted message.
// Must be called with this syntax:
// Log.Msg(F.L(), "Format using {0} {1} etc", ...);
public static void Msg(string fileLine, string format, params object[] parms)
{
string message = String.Format(format, parms);
Console.WriteLine("{0} {1}", fileLine, message);
}
}
class Program
{
static void Main(string[] args)
{
int six = 6;
string nine = "nine";
string dog = "dog";
string cat = "cats";
Log.Msg(F.L(), "The {0} chased the {1} {2}", dog, 5, cat);
Log.Msg(F.L(), "Message with no parameters");
Log.Msg(F.L(), "Message with 8 parameters {0} {1} {2} {3} {4} {5} {6} {7}",
1, 2, 3, "four", 5, 6, 7, 8.0);
Log.Msg(F.L(), "This is a message with params {0} and {1}", six, nine);
}
}
}
Here's the output from this code above
Program.cs 41: The dog chased the 5 cats
Program.cs 43: Message with no parameters
Program.cs 45: Message with 8 parameters 1 2 3 four 5 6 7 8
Program.cs 48: This is a message with params 6 and nine

Categories

Resources