I have a file that has a product ID (can only be 8 characters) followed by a new line and different prices in ascending order with respect to time on new lines. I need to print the ProductID and the latest price.
Here is an example of the contents of the file:
A1234567
200.000
300.000
B1234567
200.000
400.000
C12345678
100.00
200.00
So in this example I need to print:
A1234567: 300.00
B1234567: 400.00
I've used a regex expression to print the product IDs. But I can't figure out how to get the latest price. I was thinking of getting the line before the product ID, but not sure how to do that.
Here is the code I have:
private static void OutputCusipPrice(string filePath)
{
using (StreamReader sr = File.OpenText(filePath))
{
String s = "";
Regex r = new Regex("^[a-zA-Z0-9]*$");
int pos = 0;
while ((s = sr.ReadLine()) != null)
{
if (r.IsMatch(s) && s.Length == 8)
{
Console.WriteLine(s);
}
else
{
double result;
if (Double.TryParse(s, out result))
{
Console.WriteLine(s);
}
}
}
}
}
Please try this, Its just an implementation mentioned by #Jason Boyd
private static void OutputCusipPrice(string filePath)
{
using (StreamReader sr = File.OpenText(filePath))
{
String row = "", current="",previous = "", price = "";
bool skipInvalid = false; // This is to remove the negative case
Regex r = new Regex("^[a-zA-Z0-9]*$");
int pos = 0;
while ((row = sr.ReadLine()) != null)
{
if (r.IsMatch(row) && row.Length == 8)
{
current = row;
if (previous == "") previous = current;
if (current != previous )
{
previous = row;
Console.WriteLine("Price : " + price);
}
skipInvalid = false;
Console.WriteLine(row);
}
else
{
if (skipInvalid) continue;
double result;
if (Double.TryParse(row, out result))
{
price = result.ToString(); // cache the previous
}
else
{
skipInvalid = true;
}
}
}
if (previous != "")
{
Console.WriteLine("Price : " + price);
}
}
}
This should give you the desired result.
var input = #"A1234567
200.000
300.000
B1234567
200.000
400.000
C1234567
100.00
200.00";
var productIds = Regex.Matches(input, #".{8}\r\n")
.Cast<Match>()
.Select((m, i) => new { index = i, value = m.Value });
var prices = Regex.Split(input, #".{8}\r\n").Where(r => !string.IsNullOrWhiteSpace(r))
.Select((r, i) => new { index = i, value = r });
var result = productIds.Join(prices, pro => pro.index, pri => pri.index, (pro, pri) => new {productid = pro.value,prices=Regex.Split(pri.value,#"\r\n")
.Where(r => !string.IsNullOrWhiteSpace(r))
.Reverse().ToArray()[0]});
I'm trying to pull the tournament age from this webpage:
http://www.reddishvulcans.com/uk_tournament_database.asp
I'm trying to create a string based on the valid ages for entry for each table.
For example, if the "Carling Cup" is enterable by 7 year olds, then a string would be generated like "U7", or if it's enterable by 7, 8, and 9 year olds, the resulting string will be "U7, U8, U9".
I've made a start, however my logic will break if the ages go like this "Under 7s, Gap here where no under 8s, Under 9s".
Here is my code:
public static List<Record> getRecords()
{
string url = "http://www.reddishvulcans.com/uk_tournament_database.asp";
var Webget = new HtmlWeb();
var doc = Webget.Load(url);
var root = doc.DocumentNode;
var ages = root.SelectNodes("//div[#class='infobox']/table/tr[5]/td/img");
List<String> tournamentAges = new List<String>();
String ageGroups = "";
List<String> ageString = new List<String>();
for (Int32 i = 0; i < ages.Count(); i++)
{
if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u6_Yes.gif")
{
if (!ageString.Contains(" U6 ")) {
ageString.Add(" U6 ");
continue;
}
}
else if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u6_.gif")
{
continue;
}
if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u7_Yes.gif")
{
if (!ageString.Contains(" U7 "))
{
ageString.Add(" U7 ");
continue;
}
}
else if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u7_.gif")
{
continue;
}
if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u8_Yes.gif")
{
if (!ageString.Contains(" U8 "))
{
ageString.Add(" U8 ");
continue;
}
}
else if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u8_.gif")
{
continue;
}
// Checks until u16.gif
foreach (String a in ageString)
{
if (a != "")
{
ageGroups += a;
}
}
ageString.Clear();
if (ageGroups != "")
{
tournamentAges.Add(ageGroups);
}
ageGroups = "";
}
}
}
To be clear, I'm having trouble with the loop logic.
The flow currently goes like this:
Loop through current list of images
If > u6_Yes.gif
Concatenate u6 to ageString
else
Continue
However it will continue back to the start and get stuck in an infinite loop, How can I make it gracefully handle when u6_.gif is gone, ignore it and go to the next?
why don't you just simplify your loop like this?
if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u6_Yes.gif")
{
if (!ageString.Contains(" U6 "))
{
ageString.Add(" U6 ");
continue;
}
}
if (ages[i].GetAttributeValue("src", "nope") == "images/2016/u7_Yes.gif")
{
if (!ageString.Contains(" U7 "))
{
ageString.Add(" U7 ");
continue;
}
}
}
(...)
just remove all those else if blocks...
Also, you should consider extraction src attribute from ages array. You can use Linq and make your loop a lot simplier. Something like this:
List<String> ageString = new List<String>();
List<string> imageSources = ages.Where(x => x.GetAttributeValue("src", "nope").StartsWith("images/2016/u") && x.GetAttributeValue("src", "nope").EndsWith("_Yes.gif")).ToList();
foreach (var src in imageSources)
{
ageString.Add(" " + src.Substring(11, 2).ToUpper() + " ");
}
It's fairly straight-forward to add a TextField using ABCPDF:
public FormField AddTextField(string inRect, string inName, string inText)
{
int fieldId = mDoc.AddObject("<</Type /Annot /Subtype /Widget /F 4 /FT /Tx /Ff 4096 /Q 1>>");
mDoc.SetInfo(fieldId, "/V:Text", inText);
RegisterField(fieldId, inName, inRect);
return new FormField(fieldId, mDoc);
}
With this as the implementation:
FormField text = AddTextField("40 530 300 580", "TextField1", "Hello World!");
text.DefaultAppearance = "/TimesRoman 36 Tf 0 0 1 rg";
text.BorderColor = "0 0 0";
text.FillColor = "220 220 220";
text.TextAlign = "Left";
If I need to add two fields that have the same name, it's a little more complex:
public int AddGroupField(FormField[] inKids, string inName, string inValue)
{
if (inKids.Length == 0)
throw new Exception("Cannot have a group field with no kids");
string ft = null, dv = null;
int fieldId = mDoc.AddObject("<< /Kids [] >>");
foreach (FormField kid in inKids)
{
mDoc.SetInfo(fieldId, "/Kids[]:Ref", kid.Id.ToString());
mDoc.SetInfo(kid.Id, "/Parent:Ref", fieldId);
if (ft == null)
ft = mDoc.GetInfo(kid.Id, "/FT");
if (dv == null)
dv = mDoc.GetInfo(kid.Id, "/DV");
mDoc.SetInfo(kid.Id, "/FT:Del", "");
mDoc.SetInfo(kid.Id, "/V:Del", "");
mDoc.SetInfo(kid.Id, "/DV:Del", "");
}
mDoc.SetInfo(fieldId, "/FT", ft);
mDoc.SetInfo(fieldId, "/T:Text", inName);
mDoc.SetInfo(fieldId, "/V:Text", inValue);
if (dv != null)
mDoc.SetInfo(fieldId, "/DV:Text", dv);
int eid = mDoc.GetInfoInt(mDoc.Root, "/AcroForm:Ref");
mDoc.SetInfo(eid, "/Fields*[]:Ref", fieldId);
return fieldId;
}
With this as the implementation:
FormField[] kids = new FormField[2];
kids[0] = AddTextField("40 230 300 280", null, null);
kids[1] = AddTextField("40 170 300 220", null, null);
int id = AddGroupField(kids, "TextField1", "Hello World!");
However, I'm having issues with adding a TextField to a PDF where a TextField already exists with that same name. So, for example, if my PDF already has a field named "TextField1" and then I want to add another field with that same name, none of the above implementations will work.
I was able to get the answer from ABCPDF support. And as you can see, it's not exactly a simple process. I'm not sure anyone could just figure this out on their own without spending months and months of research on the PDF spec and the ABCPDF product.
public FormField AddTextField(string inRect, string inName, string inText)
{
bool fieldAlreadyExists = mDoc.Form[inName] != null;
int fieldId = mDoc.AddObject("<</Type /Annot /Subtype /Widget /F 4 /FT /Tx /Ff 4096 /Q 1>>");
mDoc.SetInfo(fieldId, "/V:Text", inText);
RegisterField(fieldId, inName, inRect);
var field = new FormField(fieldId, mDoc);
if (fieldAlreadyExists)
{
InteractiveForm form = new InteractiveForm(mDoc);
form.AddFieldIntoExistingGroup(field, true);
}
return field;
}
private bool AddFieldIntoExistingGroup(FormField field, bool refreshForm)
{
bool duplicatesFound = false;
int acroFormID = mDoc.GetInfoInt(mDoc.Root, "/AcroForm:Ref");
int parentID = mDoc.GetInfoInt(field.Id, "/Parent:Ref");
ArrayAtom kids;
if (parentID > 0)
{
kids = mDoc.ObjectSoup.Catalog.Resolve(Atom.GetItem(mDoc.ObjectSoup[parentID].Atom, "Kids")) as ArrayAtom;
}
else
{
kids = mDoc.ObjectSoup.Catalog.Resolve(Atom.GetItem(mDoc.ObjectSoup[acroFormID].Atom, "Fields")) as ArrayAtom;
}
Dictionary<string, List<IndirectObject>> items = new Dictionary<string, List<IndirectObject>>();
for (int i = 0; i < kids.Count; i++)
{
IndirectObject io = mDoc.ObjectSoup.Catalog.ResolveObj(kids[i]);
if (io == null)
{
continue; // shouldn't really happen
}
string name = mDoc.GetInfo(io.ID, "/T:Text");
if (!items.ContainsKey(name))
{
items[name] = new List<IndirectObject>();
}
items[name].Add(io);
}
foreach (KeyValuePair<string, List<IndirectObject>> pair in items)
{
if (pair.Value.Count > 1)
{
duplicatesFound = true;
// shift field down to be a child of a new field node
int id = mDoc.AddObject("<< >>");
if (parentID > 0)
{
mDoc.SetInfo(parentID, "/Kids[]:Ref", id);
mDoc.SetInfo(id, "/Parent:Ref", parentID);
}
else
{
mDoc.SetInfo(acroFormID, "/Fields[]:Ref", id);
}
string[] dictEntries = new[] { "/FT", "/T", "/TU", "/Ff", "/V", "/DV" };
foreach (IndirectObject io in pair.Value)
{
foreach (string dictEntry in dictEntries)
{
string val = mDoc.GetInfo(io.ID, dictEntry);
if (!string.IsNullOrEmpty(val))
{
mDoc.SetInfo(id, dictEntry, val);
mDoc.SetInfo(io.ID, dictEntry + ":Del", "");
}
}
ArrayRemoveOneRefAtom(kids, io.ID);
mDoc.SetInfo(id, "/Kids[]:Ref", io.ID);
mDoc.SetInfo(io.ID, "/Parent:Ref", id);
}
}
}
if ((refreshForm) && (duplicatesFound))
{
mDoc.Form.Refresh();
}
return duplicatesFound;
}
private static bool ArrayRemoveOneRefAtom(ArrayAtom array, int id)
{
if (array != null)
{
for (int i = 0; i < array.Count; i++)
{
RefAtom refAtom = array[i] as RefAtom;
if ((refAtom != null) && (refAtom.ID == id))
{
ArrayRemoveAt(array, i);
return true;
}
}
}
return false;
}
private static void ArrayRemoveAt(ArrayAtom array, int index)
{
if (index == 0)
{ // Workaround for bug in some versions of ABCpdf
Atom[] copy = new Atom[array.Count];
array.CopyTo(copy, 0);
array.Clear();
for (int i = 1; i < copy.Length; i++)
array.Add(copy[i]);
}
else
{
array.RemoveAt(index);
}
}
A project using .NET Compact Framework does not allow use System.Web library.
How can I do to HTMLDecode a string using .NET Compact Framework?
I didn't found any class that do that.
If you decompile the .NET Framework source you can get the methods you need. I did it for you, so you can copy and paste the two classes below:
internal class HtmlEntities
{
// Fields
private static string[] _entitiesList = new string[] {
"\"-quot", "&-amp", "<-lt", ">-gt", "\x00a0-nbsp", "\x00a1-iexcl", "\x00a2-cent", "\x00a3-pound", "\x00a4-curren", "\x00a5-yen", "\x00a6-brvbar", "\x00a7-sect", "\x00a8-uml", "\x00a9-copy", "\x00aa-ordf", "\x00ab-laquo",
"\x00ac-not", "\x00ad-shy", "\x00ae-reg", "\x00af-macr", "\x00b0-deg", "\x00b1-plusmn", "\x00b2-sup2", "\x00b3-sup3", "\x00b4-acute", "\x00b5-micro", "\x00b6-para", "\x00b7-middot", "\x00b8-cedil", "\x00b9-sup1", "\x00ba-ordm", "\x00bb-raquo",
"\x00bc-frac14", "\x00bd-frac12", "\x00be-frac34", "\x00bf-iquest", "\x00c0-Agrave", "\x00c1-Aacute", "\x00c2-Acirc", "\x00c3-Atilde", "\x00c4-Auml", "\x00c5-Aring", "\x00c6-AElig", "\x00c7-Ccedil", "\x00c8-Egrave", "\x00c9-Eacute", "\x00ca-Ecirc", "\x00cb-Euml",
"\x00cc-Igrave", "\x00cd-Iacute", "\x00ce-Icirc", "\x00cf-Iuml", "\x00d0-ETH", "\x00d1-Ntilde", "\x00d2-Ograve", "\x00d3-Oacute", "\x00d4-Ocirc", "\x00d5-Otilde", "\x00d6-Ouml", "\x00d7-times", "\x00d8-Oslash", "\x00d9-Ugrave", "\x00da-Uacute", "\x00db-Ucirc",
"\x00dc-Uuml", "\x00dd-Yacute", "\x00de-THORN", "\x00df-szlig", "\x00e0-agrave", "\x00e1-aacute", "\x00e2-acirc", "\x00e3-atilde", "\x00e4-auml", "\x00e5-aring", "\x00e6-aelig", "\x00e7-ccedil", "\x00e8-egrave", "\x00e9-eacute", "\x00ea-ecirc", "\x00eb-euml",
"\x00ec-igrave", "\x00ed-iacute", "\x00ee-icirc", "\x00ef-iuml", "\x00f0-eth", "\x00f1-ntilde", "\x00f2-ograve", "\x00f3-oacute", "\x00f4-ocirc", "\x00f5-otilde", "\x00f6-ouml", "\x00f7-divide", "\x00f8-oslash", "\x00f9-ugrave", "\x00fa-uacute", "\x00fb-ucirc",
"\x00fc-uuml", "\x00fd-yacute", "\x00fe-thorn", "\x00ff-yuml", "Œ-OElig", "œ-oelig", "Š-Scaron", "š-scaron", "Ÿ-Yuml", "ƒ-fnof", "ˆ-circ", "˜-tilde", "Α-Alpha", "Β-Beta", "Γ-Gamma", "Δ-Delta",
"Ε-Epsilon", "Ζ-Zeta", "Η-Eta", "Θ-Theta", "Ι-Iota", "Κ-Kappa", "Λ-Lambda", "Μ-Mu", "Ν-Nu", "Ξ-Xi", "Ο-Omicron", "Π-Pi", "Ρ-Rho", "Σ-Sigma", "Τ-Tau", "Υ-Upsilon",
"Φ-Phi", "Χ-Chi", "Ψ-Psi", "Ω-Omega", "α-alpha", "β-beta", "γ-gamma", "δ-delta", "ε-epsilon", "ζ-zeta", "η-eta", "θ-theta", "ι-iota", "κ-kappa", "λ-lambda", "μ-mu",
"ν-nu", "ξ-xi", "ο-omicron", "π-pi", "ρ-rho", "ς-sigmaf", "σ-sigma", "τ-tau", "υ-upsilon", "φ-phi", "χ-chi", "ψ-psi", "ω-omega", "ϑ-thetasym", "ϒ-upsih", "ϖ-piv",
" -ensp", " -emsp", " -thinsp", "-zwnj", "-zwj", "-lrm", "-rlm", "–-ndash", "—-mdash", "‘-lsquo", "’-rsquo", "‚-sbquo", "“-ldquo", "”-rdquo", "„-bdquo", "†-dagger",
"‡-Dagger", "•-bull", "…-hellip", "‰-permil", "′-prime", "″-Prime", "‹-lsaquo", "›-rsaquo", "‾-oline", "⁄-frasl", "€-euro", "ℑ-image", "℘-weierp", "ℜ-real", "™-trade", "ℵ-alefsym",
"←-larr", "↑-uarr", "→-rarr", "↓-darr", "↔-harr", "↵-crarr", "⇐-lArr", "⇑-uArr", "⇒-rArr", "⇓-dArr", "⇔-hArr", "∀-forall", "∂-part", "∃-exist", "∅-empty", "∇-nabla",
"∈-isin", "∉-notin", "∋-ni", "∏-prod", "∑-sum", "−-minus", "∗-lowast", "√-radic", "∝-prop", "∞-infin", "∠-ang", "∧-and", "∨-or", "∩-cap", "∪-cup", "∫-int",
"∴-there4", "∼-sim", "≅-cong", "≈-asymp", "≠-ne", "≡-equiv", "≤-le", "≥-ge", "⊂-sub", "⊃-sup", "⊄-nsub", "⊆-sube", "⊇-supe", "⊕-oplus", "⊗-otimes", "⊥-perp",
};
private static Hashtable _entitiesLookupTable;
private static object _lookupLockObject = new object();
internal static char Lookup(string entity)
{
if (_entitiesLookupTable == null)
{
lock (_lookupLockObject)
{
if (_entitiesLookupTable == null)
{
Hashtable hashtable = new Hashtable();
foreach (string str in _entitiesList)
{
hashtable[str.Substring(2)] = str[0];
}
_entitiesLookupTable = hashtable;
}
}
}
object obj2 = _entitiesLookupTable[entity];
if (obj2 != null)
{
return (char)obj2;
}
return '\0';
}
}
public sealed class HttpUtility
{
private static char[] s_entityEndingChars = new char[] { ';', '&' };
public static string HtmlDecode(string s)
{
if (s == null)
{
return null;
}
if (s.IndexOf('&') < 0)
{
return s;
}
StringBuilder sb = new StringBuilder();
StringWriter output = new StringWriter(sb);
HtmlDecode(s, output);
return sb.ToString();
}
public static void HtmlDecode(string s, TextWriter output)
{
if (s != null)
{
if (s.IndexOf('&') < 0)
{
output.Write(s);
}
else
{
int length = s.Length;
for (int i = 0; i < length; i++)
{
char ch = s[i];
if (ch == '&')
{
int num3 = s.IndexOfAny(s_entityEndingChars, i + 1);
if ((num3 > 0) && (s[num3] == ';'))
{
string entity = s.Substring(i + 1, (num3 - i) - 1);
if ((entity.Length > 1) && (entity[0] == '#'))
{
try
{
if ((entity[1] == 'x') || (entity[1] == 'X'))
{
ch = (char)int.Parse(entity.Substring(2), NumberStyles.AllowHexSpecifier);
}
else
{
ch = (char)int.Parse(entity.Substring(1));
}
i = num3;
}
catch (FormatException)
{
i++;
}
catch (ArgumentException)
{
i++;
}
}
else
{
i = num3;
char ch2 = HtmlEntities.Lookup(entity);
if (ch2 != '\0')
{
ch = ch2;
}
else
{
output.Write('&');
output.Write(entity);
output.Write(';');
goto Label_0103;
}
}
}
}
output.Write(ch);
Label_0103: ;
}
}
}
}
}
You could always port the code from Mono, sample VB code or sample Java code found with a simple web search.
I've used reflector in the past to find just the methods I need from the framework that aren't included and compile them directly into my compact.net project.