I am writing a C# program to analyze the the number of browsers in the UserAgent column of a web server log. I wish to output the browser type, browser major version, and the number of hits.
How can I optimize this?
I am using regex to compare the UserAgent string with predefined strings to test for Firefox, Opera, etc. I then use regex to cancel out a possible mismatch. I then use a regex to obtain the major version. I use a struct to hold this information for each browser:
private struct Browser
{
public int ID;
public string name;
public string regex_match;
public string regex_not;
public string regex_version;
public int regex_group;
}
I then load the browser information and loop over all of the records for the UserAgent:
Browser[] browsers = new Browser[5];
for (int i = 0; i < 5; i++)
{
browsers[i].ID = i;
}
browsers[0].name = "Firefox";
browsers[1].name = "Opera";
browsers[2].name = "Chrome";
browsers[3].name = "Safari";
browsers[4].name = "Internet Explorer";
browsers[0].regex_match = "(?i)firefox/([\\d\\.]*)";
browsers[1].regex_match = "(?i)opera/([\\d\\.]*)";
browsers[2].regex_match = "(?i)chrome/([\\d\\.]*)";
browsers[3].regex_match = "(?i)safari/([\\d\\.]*)";
browsers[4].regex_match = "(?i)msie([+_ ]|)([\\d\\.]*)";
browsers[0].regex_not = "(?i)flock";
browsers[1].regex_not = "";
browsers[2].regex_not = "";
browsers[3].regex_not = "(?i)android|arora|chrome|shiira";
browsers[4].regex_not = "(?i)webtv|omniweb|opera";
browsers[0].regex_version = "(?i)firefox/([\\d\\.]*)";
browsers[1].regex_version = "(?i)opera/([\\d\\.]*)";
browsers[2].regex_version = "(?i)chrome/([\\d\\.]*)";
browsers[3].regex_version = "(?i)version/([\\d\\.]*)";
browsers[4].regex_version = "(?i)msie([+_ ]|)([\\d\\.]*)";
browsers[0].regex_group = 1;
browsers[1].regex_group = 1;
browsers[2].regex_group = 1;
browsers[3].regex_group = 1;
browsers[4].regex_group = 2;
Dictionary<string, int> browser_counts = new Dictionary<string, int>();
for (int i = 0; i < 65000; i++)
{
foreach (Browser b in browsers)
{
if (Regex.IsMatch(csUserAgent[i], b.regex_match))
{
if (b.regex_not != "")
{
if (Regex.IsMatch(csUserAgent[i], b.regex_not))
{
continue;
}
}
string strBrowser = b.name;
if (b.regex_version != "")
{
string strVersion = Regex.Match(csUserAgent[i], b.regex_version).Groups[b.regex_group].Value;
int intPeriod = strVersion.IndexOf('.');
if (intPeriod > 0)
{
strBrowser += " " + strVersion.Substring(0, intPeriod);
}
}
if (!browser_counts.ContainsKey(strBrowser))
{
browser_counts.Add(strBrowser, 1);
}
else
{
browser_counts[strBrowser]++;
}
break;
}
}
}
You could
construct a hashtable or most-frequently matches user-agent and avoid matching the regexen.
store compile new Regex(pattern, RegexOptions.Compiled) instead of just pattern
combine the regexes into a single regex and take advantage of RegexOptions.Compiled and RegexOptions.CultureInvariantIgnoreCase
instead of matching twice (once with IsMatch and once with Matches) match once (Matches) and check whether the MatchCollection is empty
This is only a starting point - I might come up with more ideas on reading the code :)
Edit One more:
avoid parsing the version with another regex - only safari requires special treaetment according to your config. Try to 'catch' the version with the same regex as the browserid. (I'd simply make an exception for safari for now)
E.g. you could have a single static regex instance like this:
private static readonly Regex _regex = new Regex(
"(?i)"
+ "(?<browserid>(?:firefox/|opera/|chrome/|chrome/|safari/|msie[+_ ]?))"
+ "(?<version>[\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
You can conveniently access the proper subgroups by using match.Groups["browserid"] and match.Groups["version"]. This nearly eliminates all the use for your list of Browser structs.
The only thing it still caters for is the exclusion regex (regex_not). I suggest re-profiling with the single positive regex first, though and see whether there is still a performance problem left before frying smaller fish.
Benchmark
I wrote a benchmark (see below). I'll be updating this incrementally until I loose interest :) (I know my dataset isn't representative. If you upload a file, I'll test it with that)
replacing the separate regexes by the single statically compiled regex, speeds up from 14s to 2.1s (a 6x speedup); this is only with the outermost match replaced
replacing the regex_not/regex_version by precompiled regexes did not make much of a difference with my test set (but I don't have actual matching useragents, so that makes sense)
.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class Program
{
private struct Browser
{
public int ID;
public string name;
public Regex regex_match, regex_not, regex_version;
public int regex_group;
}
private static readonly Regex _regex = new Regex("(?i)"
+ "(?<browserid>(?:firefox/|opera/|chrome/|chrome/|safari/|msie[+_ ]?))"
+ "(?<version>[\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
public static void Main(string[] args)
{
Browser[] browsers = new Browser[5];
for (int i = 0; i < 5; i++)
{
browsers[i].ID = i;
}
browsers[0].name = "Firefox";
browsers[1].name = "Opera";
browsers[2].name = "Chrome";
browsers[3].name = "Safari";
browsers[4].name = "Internet Explorer";
browsers[0].regex_match = new Regex("(?i)firefox/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[1].regex_match = new Regex("(?i)opera/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[2].regex_match = new Regex("(?i)chrome/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[3].regex_match = new Regex("(?i)safari/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[4].regex_match = new Regex("(?i)msie([+_ ]|)([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
// OPTIMIZATION #2
browsers[0].regex_not = new Regex("(?i)flock", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[1].regex_not = null;
browsers[2].regex_not = null;
browsers[3].regex_not = new Regex("(?i)android|arora|chrome|shiira", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[4].regex_not = new Regex("(?i)webtv|omniweb|opera", RegexOptions.Compiled | RegexOptions.CultureInvariant);
// OPTIMIZATION #2
browsers[0].regex_version = new Regex("(?i)firefox/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[1].regex_version = new Regex("(?i)opera/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[2].regex_version = new Regex("(?i)chrome/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[3].regex_version = new Regex("(?i)version/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[4].regex_version = new Regex("(?i)msie([+_ ]|)([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[0].regex_group = 1;
browsers[1].regex_group = 1;
browsers[2].regex_group = 1;
browsers[3].regex_group = 1;
browsers[4].regex_group = 2;
Dictionary<string, int> browser_counts = new Dictionary<string, int>();
var lookupBrowserId = new Dictionary<string, int> {
{ "firefox/", 0 },
{ "opera/", 1 },
{ "chrome/", 2 },
{ "safari/", 3 },
{ "msie+", 4 },
{ "msie_", 4 },
{ "msie ", 4 },
{ "msie", 4 },
};
for (int i=1; i<20; i++)
foreach (var line in System.IO.File.ReadAllLines("/etc/dictionaries-common/words"))
{
// OPTIMIZATION #1 START
Match match = _regex.Match(line);
{
if (match.Success)
{
Browser b = browsers[lookupBrowserId[match.Groups["browserid"].Value]];
// OPTIMIZATION #1 END
// OPTIMIZATION #2
if (b.regex_not != null && b.regex_not.IsMatch(line))
continue;
string strBrowser = b.name;
if (b.regex_version != null)
{
// OPTIMIZATION #2
string strVersion = b.regex_version.Match(line).Groups[b.regex_group].Value;
int intPeriod = strVersion.IndexOf('.');
if (intPeriod > 0)
{
strBrowser += " " + strVersion.Substring(0, intPeriod);
}
}
if (!browser_counts.ContainsKey(strBrowser))
{
browser_counts.Add(strBrowser, 1);
}
else
{
browser_counts[strBrowser]++;
}
break;
}
}
}
}
}
Related
This following code gives me the error below . I think I need "InvokeRequired" . But I don't understand how can I use?
error:Cross-thread operation not valid: Control 'statusBar1' accessed from a thread other than the thread it was created on.
the code :
public void CalculateGeneration(int nPopulation, int nGeneration)
{
int _previousFitness = 0;
Population TestPopulation = new Population();
for (int i = 0; i < nGeneration; i++)
{
if (_threadFlag)
break;
TestPopulation.NextGeneration();
Genome g = TestPopulation.GetHighestScoreGenome();
if (i % 100 == 0)
{
Console.WriteLine("Generation #{0}", i);
if ( ToPercent(g.CurrentFitness) != _previousFitness)
{
Console.WriteLine(g.ToString());
_gene = g;
statusBar1.Text = String.Format("Current Fitness = {0}", g.CurrentFitness.ToString("0.00"));
this.Text = String.Format("Sudoko Grid - Generation {0}", i);
Invalidate();
_previousFitness = ToPercent(g.CurrentFitness);
}
if (g.CurrentFitness > .9999)
{
Console.WriteLine("Final Solution at Generation {0}", i);
statusBar1.Text = "Finished";
Console.WriteLine(g.ToString());
break;
}
}
}
}
Easiest for reusability is to add a helper function like:
void setstatus(string txt)
{
Action set = () => statusBar1.Text = txt;
statusBar1.Invoke(set);
}
Or with the invokerequired check first:
delegate void settextdelegate(string txt);
void setstatus(string txt)
{
if (statusBar1.InvokeRequired)
statusBar1.Invoke(new settextdelegate(setstatus), txt);
else
statusBar1.Text = txt;
}
Either way the status can then be set like
setstatus("Finished");
For completeness I should add that even better would be to keep your calculating logic separated from your form and raise a status from within your calculating functionality that can be hanled by the form, but that could be completely out of scope here.
public List<Health_Scheme_System.Employee> GetPenEmployeeTable()
{
Health_Scheme_System.Health_Scheme_SystemDB db = new Health_Scheme_System.Health_Scheme_SystemDB();
var x = (from c in db.Employees
where c.Pensioners.Equals (1)
select c);
return x.ToList();
}
//Selecting multiple columns from an HR view table together with the scheme name of scheme.
public List<EmployeesX> GetPensioners()
{
Health_Scheme_System.Health_Scheme_SystemDB db = new Health_Scheme_System.Health_Scheme_SystemDB();
List<Health_Scheme_System.EmployeeDirectory> listEmployeeView = GetPenEmployeeView();
List<Health_Scheme_System.Employee> listEmployeeTable = GetPenEmployeeTable();
List<Health_Scheme_System.Scheme> listSchemes = GetSchemes();
List<EmployeesX> listOfEmployees = new List<EmployeesX>();
//checking for comparision of getemployeeview to getemployee table and then to getschemes
//Then display the scheme name if they are similar.
for (int i = 0; i < listEmployeeView.Count; i++)
{
EmployeesX emp = new EmployeesX();
emp.ID_NO = listEmployeeView[i].ID_NO;
emp.FIRST_NAME = listEmployeeView[i].FIRST_NAME;
emp.LAST_NAME = listEmployeeView[i].LAST_NAME;
emp.LOCATION_CODE = listEmployeeView[i].LOCATION_CODE;
for (int j = 0; j < listEmployeeTable.Count; j++)
{
if (listEmployeeTable[j].EmployeeIDCard == listEmployeeView[i].ID_NO)
{
emp.Pensioners = listEmployeeTable[j].Pensioners;
for (int k = 0; k < listSchemes.Count; k++)
{
if (listEmployeeTable[j].SchemeID == listSchemes[k].SchemeID)
{
emp.SCHEME_NAME = listSchemes[k].Name;
emp.START_DATE = listEmployeeTable[j].StartSchemeDate;
}
}
}
}
listOfEmployees.Add(emp);
}
return listOfEmployees;
}
How can I make the same method with using .equals??
Have you tried this:
var x = (from c in db.Employees
where c.Pensioners == 1
select c)
Additional info:
If you use a method on an object in a linq query subsonic needs to know how to translate that into pur SQL code. That does not work by default and must be implemented for every known method on every supported type for every dataprovider (if differs from default implementation). So there is a bunch of work to do for subsonic.
A good starting point for knowning what's supported and what not is the TSqlFormatter class. Have a look at protected override Expression VisitMethodCall(MethodCallExpression m)
https://github.com/subsonic/SubSonic-3.0/blob/master/SubSonic.Core/Linq/Structure/TSqlFormatter.cs
There is already an implementation for Equals
else if (m.Method.Name == "Equals")
{
if (m.Method.IsStatic && m.Method.DeclaringType == typeof(object))
{
sb.Append("(");
this.Visit(m.Arguments[0]);
sb.Append(" = ");
this.Visit(m.Arguments[1]);
sb.Append(")");
return m;
}
else if (!m.Method.IsStatic && m.Arguments.Count == 1 && m.Arguments[0].Type == m.Object.Type)
{
sb.Append("(");
this.Visit(m.Object);
sb.Append(" = ");
this.Visit(m.Arguments[0]);
sb.Append(")");
return m;
}
else if (m.Method.IsStatic && m.Method.DeclaringType == typeof(string))
{
//Note: Not sure if this is best solution for fixing side issue with Issue #66
sb.Append("(");
this.Visit(m.Arguments[0]);
sb.Append(" = ");
this.Visit(m.Arguments[1]);
sb.Append(")");
return m;
}
}
I suppose Prnsioners is an integer type so you basically have to add another else if and recomplie subsonic.
This should work but I haven't tested it.
else if (!m.Method.IsStatic && m.Method.DeclaringType == typeof(int))
{
sb.Append("(");
this.Visit(m.Arguments[0]);
sb.Append(" = ");
this.Visit(m.Arguments[1]);
sb.Append(")");
return m;
}
(or you can try the == approach like in the example on the top).
I am trying to implement simple paging on my sharepoint webpart. I have a single news articles list which has some simple columns. I want to be able to have then five on a page and with some numerical paging at the bottom. I have gone through the net trying to understand splistitemcollectionposition but with no luck. If anyone can help please can you give me a simple code example or some guidanc
Many thanks
Chris
I would suggest using SPDataSource and a SPGridView, together they will implement paging and many other cool features with minimal or no code.
Use this a a guide for some of the classes/methods/properties you might need to use to get paging to work. Be aware that this code does not compile, i have just pulled together various code snippets that i have in my own list results framework, which includes paging, sorting, grouping and caching. It should be enough to get you started though.
public class PagedListResults : System.Web.UI.WebControls.WebParts.WebPart {
protected SPPagedGridView oGrid;
protected override void CreateChildControls() {
this.oGrid = new SPPagedGridView();
oGrid.AllowPaging = true;
oGrid.PageIndexChanging += new GridViewPageEventHandler(oGrid_PageIndexChanging);
oGrid.PagerTemplate = null; // Must be called after Controls.Add(oGrid)
oGrid.PagerSettings.Mode = PagerButtons.NumericFirstLast;
oGrid.PagerSettings.PageButtonCount = 3;
oGrid.PagerSettings.Position = PagerPosition.TopAndBottom;
base.CreateChildControls();
}
public override void DataBind() {
base.DataBind();
SPQuery q = new SPQuery();
q.RowLimit = (uint)info.PageSize;
if (!string.IsNullOrEmpty(info.PagingInfoData)) {
SPListItemCollectionPosition pos = new SPListItemCollectionPosition(info.PagingInfoData);
q.ListItemCollectionPosition = pos;
} else {
//1st page, dont need a position, and using a position breaks things
}
q.Query = info.Caml;
SPListItemCollection items = SPContext.Current.List.GetItems(q);
FilterInfo info = null;
string tmp = "<View></View>";
tmp = tmp.Replace("<View><Query>", string.Empty);
tmp = tmp.Replace("</Query></View>", string.Empty);
info.Caml = tmp;
info.PagingInfoData = string.Empty;
info.CurrentPage = oGrid.CurrentPageIndex;
info.PageSize = oGrid.PageSize;
if (oGrid.PageIndex == 0 || oGrid.CurrentPageIndex == 0) {
//do nothing
} else {
StringBuilder value = new StringBuilder();
value.Append("Paged=TRUE");
value.AppendFormat("&p_ID={0}", ViewState[KEY_PagingPrefix + "ID:" + oGrid.PageIndex]);
info.PagingInfoData = value.ToString();
}
int pagecount = (int)Math.Ceiling(items.Count / (double)oGrid.PageSize);
for (int i = 1; i < pagecount; i++) { //not always ascending index numbers
ResultItem item = items[(i * oGrid.PageSize) - 1];
ViewState[KEY_PagingPrefix + "ID:" + i] = item.ID;
}
oGrid.VirtualCount = items.Count;
DateTime time3 = DateTime.Now;
DataTable table = new DataTable("Data");
DataBindListData(table, items);
this.oGrid.DataSource = table;
this.oGrid.DataBind();
this.oGrid.PageIndex = oGrid.CurrentPageIndex; //need to reset this after DataBind
}
void oGrid_PageIndexChanging(object sender, GridViewPageEventArgs e) {
oGrid.PageIndex = e.NewPageIndex;
oGrid.CurrentPageIndex = oGrid.PageIndex;
}
}
public class FilterInfo {
public string Caml;
public string PagingInfoData;
public int CurrentPage;
public int PageSize;
}
public class SPPagedGridView : SPGridView {
protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource) {
pagedDataSource.AllowCustomPaging = true;
pagedDataSource.VirtualCount = virtualcount;
pagedDataSource.CurrentPageIndex = currentpageindex;
base.InitializePager(row, columnSpan, pagedDataSource);
}
private int virtualcount = 0;
public int VirtualCount {
get { return virtualcount; }
set { virtualcount = value; }
}
private int currentpageindex = 0;
public int CurrentPageIndex {
get { return currentpageindex; }
set { currentpageindex = value; }
}
}
check out my post on how to page using SPListItemCollectionPosition, I did a component to page over lists, maybe it can help -> http://hveiras.wordpress.com/2011/11/07/listpagert-using-splistitemcollectionposition/
I'm trying to find the easiest way to search a string for an array of possible strings. I know the easy way to do this for characters is to use myString.IndexOfAny(charArray). But how what if I'd like to search my string for strings and not just characters? Are there any .net tricks or methods that make this easier?
Basically, I'd like to do something like this:
string myName = "rahkim";
string[] names = new string[] {"joe","bob","chris"};
if(myName.IndexOfAny(names) >= 0)
{
//success code//
}
I know there are ways to do this with loops, etc. But I was hoping for something inherent in the framework.
You should define if you want to to find equal strings or search for a matching substring. Both ways are easy pre-LINQ and with LINQ.
string myName = "rahkim";
string[] names = new string[] { "joe", "bob", "chris" };
Equal Strings, LINQ
bool contains = names.Contains(myName);
Equal Strings, Pre-LINQ
bool contains = new List<string>(name).Contains(myName);
Substrings, LINQ
bool contains = names.Any(name => name.Contains(myName));
Substring, Pre-LINQ
bool contains = false;
foreach(string name in names)
if (name.Contains(myName))
contains = true;
If anyone else found this while trying to search for a .Net method like String.IndexOfAny(String[]), this is my solution:
C#
public int IndexOfAny(string test, string[] values)
{
int first = -1;
foreach (string item in values) {
int i = test.IndexOf(item);
if (i >= 0) {
if (first > 0) {
if (i < first) {
first = i;
}
} else {
first = i;
}
}
}
return first;
}
VB
Public Function IndexOfAny(test As String, values As String()) As Integer
Dim first As Integer = -1
For Each item As String In values
Dim i As Integer = test.IndexOf(item)
If i >= 0 Then
If first > 0 Then
If i < first Then
first = i
End If
Else
first = i
End If
End If
Next
Return first
End Function
You can do a LastIndexOfAny(String[]) by just switching the
i < first
to
i > first
You can (also) use the static IndexOf method of the Array class:
bool hasName = Array.IndexOf(names, myName) > -1;
int IndexOfAny(String[] rgs) would indeed be nice but it's nominally an O(n^2) operation. If, in your application, the set of strings rgs is large and always the same, the most efficient approach is to load them into a trie data structure once, and then use the trie repeatedly to search for them within the unknown strings given at runtime.
Here is the relevant code, adapted from a C# trie source I found on the web, attributed to "Kerry D. Wong." In my version, each string in the trie has a "payload" of generic type TValue. To use this trie to simply search for substrings, the payload could always be set to true, as illustrated with simple_trie.
The other thing I changed here is that this trie automatically adapts allow for storage of arbitrary Unicode strings. The array at each node—which characterizes a trie—adjusts its base and length to accomodate the range of Unicode characters which need to be stored at that node. This allows for case-sensitive matching, for example.
The C# 3.0 initialization syntax is handy for this trie, but enabling it requires a dummy implementation of IEnumerable in order to compile. The CLR doesn't seem to call GetEnumerator() and I suggest that you don't try to enumerate with its result either.
using System;
using System.Collections.Generic;
using System.Linq; // only used in Main()
class Program
{
// trie with payload of type <String>
static Trie<String> value_trie = new Trie<String>
{
{ "rabbit", "cute" },
{ "giraffe", "tall" },
{ "ape", "smart" },
{ "hippo", "large" },
};
// degenerate case of a trie without payload
static Trie<bool> simple_trie = new Trie<bool>
{
{ "rabbit", true },
{ "giraffe", true },
{ "ape", true },
{ "hippo", true },
};
static void Main(String[] args)
{
String s = "Once upon a time, a rabbit met an ape in the woods.";
// Retrieve payloads for words in the string.
//
// output:
// cute
// smart
foreach (String word in value_trie.AllSubstringValues(s))
Console.WriteLine(word);
// Simply test a string for any of the words in the trie.
// Note that the Any() operator ensures that the input is no longer
// traversed once a single result is found.
//
// output:
// True
Console.WriteLine(simple_trie.AllSubstringValues(s).Any(e=>e));
s = "Four score and seven years ago.";
// output:
// False
Console.WriteLine(simple_trie.AllSubstringValues(s).Any(e => e));
}
}
class TrieNode<TValue>
{
private TrieNode<TValue>[] nodes = null;
private TValue m_value = default(TValue);
private Char m_base;
public Char Base { get { return m_base; } }
public bool IsEnd { get { return !m_value.Equals(default(TValue)); } }
public TValue Value
{
get { return m_value; }
set { m_value = value; }
}
public IEnumerable<TrieNode<TValue>> Nodes { get { return nodes; } }
public TrieNode<TValue> this[char c]
{
get
{
if (nodes != null && m_base <= c && c < m_base + nodes.Length)
return nodes[c - m_base];
return null;
}
}
public TrieNode<TValue> AddChild(char c)
{
if (nodes == null)
{
m_base = c;
nodes = new TrieNode<TValue>[1];
}
else if (c >= m_base + nodes.Length)
{
Array.Resize(ref nodes, c - m_base + 1);
}
else if (c < m_base)
{
Char c_new = (Char)(m_base - c);
TrieNode<TValue>[] tmp = new TrieNode<TValue>[nodes.Length + c_new];
nodes.CopyTo(tmp, c_new);
m_base = c;
nodes = tmp;
}
TrieNode<TValue> node = nodes[c - m_base];
if (node == null)
{
node = new TrieNode<TValue>();
nodes[c - m_base] = node;
}
return node;
}
};
class Trie<TValue> : System.Collections.IEnumerable
{
private TrieNode<TValue> _root = new TrieNode<TValue>();
// This dummy enables C# 3.0 initialization syntax
public System.Collections.IEnumerator GetEnumerator()
{
return null;
}
public void Add(String s, TValue v)
{
TrieNode<TValue> node = _root;
foreach (Char c in s)
node = node.AddChild(c);
node.Value = v;
}
public bool Contains(String s)
{
TrieNode<TValue> node = _root;
foreach (Char c in s)
{
node = node[c];
if (node == null)
return false;
}
return node.IsEnd;
}
public TValue Find(String s_in)
{
TrieNode<TValue> node = _root;
foreach (Char c in s_in)
{
node = node[c];
if (node == null)
return default(TValue);
}
return node.Value;
}
public IEnumerable<TValue> FindAll(String s_in)
{
TrieNode<TValue> node = _root;
foreach (Char c in s_in)
{
node = node[c];
if (node == null)
break;
if (node.Value != null)
yield return node.Value;
}
}
public IEnumerable<TValue> AllSubstringValues(String s)
{
int i_cur = 0;
while (i_cur < s.Length)
{
TrieNode<TValue> node = _root;
int i = i_cur;
while (i < s.Length)
{
node = node[s[i]];
if (node == null)
break;
if (node.Value != null)
yield return node.Value;
i++;
}
i_cur++;
}
}
};
Here's the right syntax:
if(names.Contains(myName))
{
//success code//
}
if (names.Contains(myName))
{
//success code//
}
What would be a simple implementation of a method to convert a String like "Hello there everyone" to "helloThereEveryone". In JavaME support for String and StringBuffer utility operations are quite limited.
Quick primitive implementation. I have no idea of restrictions of J2ME, so I hope it fits or it gives some ideas...
String str = "Hello, there, everyone?";
StringBuffer result = new StringBuffer(str.length());
String strl = str.toLowerCase();
boolean bMustCapitalize = false;
for (int i = 0; i < strl.length(); i++)
{
char c = strl.charAt(i);
if (c >= 'a' && c <= 'z')
{
if (bMustCapitalize)
{
result.append(strl.substring(i, i+1).toUpperCase());
bMustCapitalize = false;
}
else
{
result.append(c);
}
}
else
{
bMustCapitalize = true;
}
}
System.out.println(result);
You can replace the convoluted uppercase append with:
result.append((char) (c - 0x20));
although it might seem more hackish.
With CDC, you have:
String.getBytes();//to convert the string to an array of bytes
String.indexOf(int ch); //for locating the beginning of the words
String.trim();//to remove spaces
For lower/uppercase you need to add(subtract) 32.
With these elements, you can build your own method.
private static String toCamelCase(String s) {
String result = "";
String[] tokens = s.split("_"); // or whatever the divider is
for (int i = 0, L = tokens.length; i<L; i++) {
String token = tokens[i];
if (i==0) result = token.toLowerCase();
else
result += token.substring(0, 1).toUpperCase() +
token.substring(1, token.length()).toLowerCase();
}
return result;
}
Suggestion:
May be if you can port one regexp library on J2ME, you could use it to strip spaces in your String...
Try following code
public static String toCamel(String str) {
String rtn = str;
rtn = rtn.toLowerCase();
Matcher m = Pattern.compile("_([a-z]{1})").matcher(rtn);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, m.group(1).toUpperCase());
}
m.appendTail(sb);
rtn = sb.toString();
return rtn;
}
I would suggest the following simple code:
String camelCased = "";
String[] tokens = inputString.split("\\s");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i];
camelCased = camelCased + token.substring(0, 1).toUpperCase() + token.substring(1, token.length());
}
return camelCased;
I would do it like this:
private String toCamelCase(String s) {
StringBuffer sb = new StringBuffer();
String[] x = s.replaceAll("[^A-Za-z]", " ").replaceAll("\\s+", " ")
.trim().split(" ");
for (int i = 0; i < x.length; i++) {
if (i == 0) {
x[i] = x[i].toLowerCase();
} else {
String r = x[i].substring(1);
x[i] = String.valueOf(x[i].charAt(0)).toUpperCase() + r;
}
sb.append(x[i]);
}
return sb.toString();
}
check this
import org.apache.commons.lang.WordUtils;
String camel = WordUtils.capitalizeFully('I WANT TO BE A CAMEL', new char[]{' '});
return camel.replaceAll(" ", "");