I have textfiles, which have attributes saved in Strings. Those Strings have a pattern like this:
[attributeName]:[value]
I can't generalize the [value], because it could be of any primitive datatype.
Saving the effectively values is not my concern, because it's depending on the user which attribute has to be loaded. The same file won't be loaded very often.
Now I have 2 problems:
1) For some reason the program which creates those files sometimes adds spaces around the : at some attributes and [value] could also contain spaces, so I have to get rid of those
2) Making the reading of those attributes more performant:
I've come up with this method:
public String getAttribute(File file, String attribute)
{
try
{
BufferedReader reader = new BufferedReader(new FileReader(file), 1024);
String line;
Pattern p = Pattern.compile(Pattern.quote(attribute), Pattern.CASE_INSENSITIVE);
while ((line = reader.readLine()) != null)
{
int i = line.indexOf(":");
if(line.charAt(i-1) == ' ')
line = line.substring(0,i-2) + line.substring(i);
if(line.charAt(i+1) == ' ')
line = line.substring(0,i) + line.substring(i+2);
if (p.matcher(line).find())
{
return line.replace(attribute, "").trim();
}
}
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
However, this method will probably be one of the most called by my application, so I can't leave it so unperformant as it is right now,
Thanks for any help!
I modified code to find appropriate line. Check example code below.
If you have a lot of files and attributes in these files you could think about saving somewhere pair attribute=value in code. In example code I provided very primitive cache by using Table interface from guava library.
Example code:
# guava library
import com.google.common.collect.Table;
import com.google.common.collect.HashBasedTable;
# apache commons lang
import static org.apache.commons.lang.StringUtils.startsWithIgnoreCase;
# apache commons io
import static org.apache.commons.io.IOUtils.closeQuietly;
[...]
# very primitive cache implementation. To find a value in table you have to
# pass row and column keys. In this implementation row is equal to file
# absolute path (because you can have 2 files with the same name) and column
# is equal to attribute name.
# If you have a lot of files and attributes probably you will have to clear
# from time to time the cache otherwise you will get out of memory
private static final Table<String, String, String> CACHE = HashBasedTable.create();
[...]
public String getAttribute(File file, String attribute) {
# get value for the given attribute from the given file
String value = CACHE.get(file.getAbsolutePath(), attribute);
# if cache does not contain value, method will read value from file
if (null == value) {
BufferedReader reader = null;
String value = null;
try {
reader = new BufferedReader(new FileReader(file), 1024);
String line;
while ((line = reader.readLine()) != null) {
# From your description I understood that each line in file
# starts with attribute name
if (startsWithIgnoreCase(line, attribute) {
# if we found correct line we simple split it by ':'
String[] array = line.split(":");
# this is to ensure that line contains attribute name
# and value
if (array.length >= 2) {
# we found value for attribute and we remove spaces
value = array[1].trim();
# we put value to the cache to speed up finding
# value for the same attribute in the future
CACHE.put(file.getAbsolutePath(), attribute, value);
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
# you should always close
closeQuietly(reader);
}
}
return value;
}
Related
I am trying to understand how this convertingStringToInt method works. I am reading a file, storing the values in an array and am to pass those values to the method to be converted. In the parameters of convertingStringToInt, I have (String number) I don't get where the String "number" is getting its values. So I am passing in a string called numbers, but how is that newly created String associated with any of the values in my file...?!?
I am trying to understand the cause all the return numbers are the error code -460 except the last digit in the file. So the String numbers is associated with the file somehow I just don't get how...
public static void read_file()
{
try {
File file = new File("randomNumbers.txt");
Scanner scan = new Scanner(file);
int amountOfNumbersInFile = convertingStringToInt(scan.nextLine()); // read the first line which is 100 to set array size
global_numbers = new int[amountOfNumbersInFile]; // set the array size equal to the first line read which is 100
for (int index = 0; index < amountOfNumbersInFile; index++)
{
String line = scan.nextLine();
global_numbers [index] = convertingStringToInt(line);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static int convertingStringToInt(String numbers) //what does string "number" equal? why/where is it declared?
{
String numbers = scan.nextInt();
try {
return Integer.parseInt(numbers);
} catch (NumberFormatException n) {
return -460;
}
}
I have global_numbers declared as a global variable.
so the first thing u need understand is what u have in your txt file
if in this file you have only number is ok use stringToInt
but if you have words this never work properly
I want to know, how it's possible to react on a in a groovy script.
I'm using a While controller to iterate through all lines in the CSV and generate JMeter variables before my actual testplan. I need to do this several times for different CSV files, therefore I don't want to stop the thread at in the While controller.
I imagined something like this:
if (${CSV_VALUE1} != "<EOF>")
{
def variableName = sprintf('%1$sVALUE',[${CSV_VALUE2}])
vars.put(variableName,${CSV_VALUE1});
}
CSV_VALUE1 is the value for the JMeter variable and CSV_VALUE2 is the name of the variable.
Testplan
I also appreciate better solutions, which iterate through every row of the CSV file and generate JMeter variables according to my conventions of it. A constraint is, that it has to be done in only one single thread group (=> No stopping of threads on EOF)
You can use "BeanShell" to read "CSV file", below is sample csv file, which has below data
answer1,0
answer2,1
answer3,2
...
answerX,X-1
To read this file use below "Beanshell" script
import java.text.*;
import java.io.*;
import java.util.*;
String filename = "oprosnik_" + vars.get("fileNum") + ".csv";
ArrayList strList = new ArrayList();
try {
File file = new File(filename);
if (!file.exists()) {
throw new Exception ("ERROR: file " + filename + " not found");
}
BufferedReader bufRdr = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
String line = null;
Integer i = 0;
while((line = bufRdr.readLine()) != null) {
strList.add(line);
i++;
}
bufRdr.close();
counter = Integer.parseInt(vars.get("counter"));
if (counter != i) {
String[] variables = strList.get(counter).split(",");
vars.put("answer",variables[0]);
vars.put("answerNum",variables[1]);
counter++;
vars.put("counter",Integer.toString(counter));
}
else {
vars.put("answer","<EOF>");
vars.put("eol","<EOF>");
vars.put("counter","0");
}
}
catch (Exception ex) {
IsSuccess = false;
log.error(ex.getMessage());
System.err.println(ex.getMessage());
}
catch (Throwable thex) {
System.err.println(thex.getMessage());
}
For reference check following link
You can handle this <EOF> case using If Controller and While Controller combination like:
While Controller: condition ${__javaScript("${CSV_VALUE1}" != "<EOF>",)}
If Controller: condition "${CSV_VALUE1}" != "<EOF>"
READ - Action Models
JSR223 Sampler
...
See Using the While Controller in JMeter article for details
It's possible to detect the end of file for a CSV data set by using a simple if-condition with quotes for the executing block:
if ("${CSV_VALUE1}" != "<EOF>")
{
//Code to execute if the condition is satisfied
}
I would like to get a list of most possible list of tokens for a given location in the text (line and column number) to determine what has to be populated for auto code completion. Can this be easily achieved using ANTLR 4 API.
I want to get the possible list of tokens for a given location because the user might be writing/editing somewhere in the middle of the text which still guarantees the possible list of tokens.
Please give me some guidelines because I was unable to find an online resource on this topic.
One way to get tokens by line number is to create a ParseTreeListener for your grammar, use it to walk a given ParseTree and index TerminalNodes by line number. I don't know C#, but here is how I've done it in Java. Logic should be similar.
public class MyLineIndexer extends MyGrammarParserBaseListener {
protected MultiMap<Integer, TerminalNode> filelineTokenIndex;
#Override
public void visitTerminal(#NotNull TerminalNode node) {
// map every token to its file line for searching later...
if ( node.getSymbol() != null ) {
List<TerminalNode> tokens;
Integer line = node.getSymbol().getLine();
if (!filelineTokenIndex.containsKey(line)) {
tokens = new ArrayList<>();
filelineTokenIndex.put(line, tokens);
} else {
tokens = filelineTokenIndex.get(line);
}
tokens.add(node);
}
super.visitTerminal(node);
}
}
then walk the parse tree the usual way...
ParseTree parseTree = ... ; // parse it how you want to
MyLineIndexer indexer = new MyLineIndexer();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(indexer, parseTree);
Getting the token at a line and range is now reasonably straight forward and efficient assuming you have a reasonable number of tokens on a line. For example you can add another method to the Listener like this:
public TerminalNode findTerminalNodeAtCaret(int caretPos, int caretLine) {
if (caretPos <= 0) return null;
if (this.filelineTokenIndex.containsKey(caretLine)) {
List<TerminalNode> nodes = filelineTokenIndex.get(caretLine);
if (nodes.size() == 0) return null;
int tokenEndPos, tokenStartPos;
for (TerminalNode n : nodes) {
if (n.getSymbol() != null) {
tokenEndPos = n.getSymbol().getCharPositionInLine() + n.getText().length();
tokenStartPos = n.getSymbol().getCharPositionInLine();
// If the caret is within this token, return this token
if (caretPos >= tokenStartPos && caretPos <= tokenEndPos) {
return n;
}
}
}
}
return null;
}
You will also need to ensure your parser allows for 'loose' parsing. While a language construct is being typed, it is likely not to be valid. Your Parser rules should allow for this.
I've got some C# code like this (class file = Status.cs):
/// <summary>
/// Constructs a status entity with the text specified
/// </summary>
/// <param name="someParameter">Some parameter.</param>
public Status(string someParameter)
{
SomeProperty = someParameter;
}
/// <summary>
/// An example of a virtual property.
/// </summary>
public virtual string SomeProperty { get; private set; }
And I want to do 3 things to it:
perform a Resharper "to property with backing field" on it
get rid of the "private set" and replace it with a regular "set"
change the constructor so it initializes the private field instead of the property
So the end result would look like this:
/// <summary>
/// Constructs a status entity with the text specified
/// </summary>
/// <param name="someParameter">Some parameter.</param>
public Status(string someParameter)
{
_someProperty = someParameter;
}
private string _someProperty;
/// <summary>
/// An example of a virtual property.
/// </summary>
public virtual string SomeProperty
{
get { return _someProperty; }
set { _someProperty = value; }
}
And my question is: Is there a way to automate this type of refactoring using, say, the Resharper API ?
Background:
For those who might wonder why I want to do this, it's because:
I'm upgrading NHibernate (old=2.1.2.4000, new=3.3.1.4000) and Fluent NHibernate (old=1.1.0.685, new=1.3.0.0).
I've got rid of the old NHibernate.ByteCode.Castle.dll and the corresponding line in the config file, so I can now use the default proxy that's built into the latest NHibernate.
Between the new implementation of NHibernate and the new version of Fluent, there seem to be two problems when I try to build and run unit tests (part of this is FxCop complaining, but anyway):
a) exceptions are thrown because of the "private set", and
b) exceptions are thrown because the virtual property is being initialized in the constructor.
So I found that if I make those changes, it compiles and the unit tests pass.
So that's fine for a class or two, but there are over 800 class files and who knows how many properties.
I'm sure there are lots of ways to do this (e.g. using reflection, recursing through the directories and parsing the files etc), but it seems like Resharper is the proper tool for something like this.
Any help appreciated, thank you, -Dave
--In response to the answer saying "just change it to a protected set and you're done":
Unfortunately it’s not that simple.
Here is the error that occurs on running unit tests (before making any changes to any class):
Test method threw exception:
NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
.Status: method set_StatusText should be 'public/protected virtual' or 'protected internal virtual'
..Status: method set_Location should be 'public/protected virtual' or 'protected internal virtual'
So if I change the class as suggested (where the only change is to change the “private set” to a “protected set”), the project will not build, because:
Error 2 CA2214 : Microsoft.Usage : 'Status.Status(string, StatusLocation)' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences:
Status..ctor(String, StatusLocation)
Status.set_Location(StatusLocation):Void C:\\Status.cs 28
That is why it is also necessary to change any statement in the constructor which initializes one of these virtual properties.
The previous implementation of the NHibernate proxy (ByteCode.Castle) did not seem to care about the “private set”, whereas this one does.
And, admittedly, the second error is because of FxCop, and I could just put an attribute on the class to tell FxCop not to complain about this, but that seems to just be making the problem go away, and initializing virtual properties in constructors is, as I understand it, bad practice anyway.
So my question still stands. The changes I initially described are the changes I would like to make. How can I automate these changes?
I went ahead and wrote a C# utility to parse such a class file. The "protected set" idea is valid to a point (thanks Hazzik), but it still needs a backing field. The below code produces the output I described above (except uses a "protected set"). Regards, -Dave
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
// TODO: write recursive algorithm to loop through directories
// TODO: handle generic collections as Fluent NHibernate treats those differently
class Program
{
public static string ConvertInitialCapitalToUnderscoreAndLowerCase(string input)
{
var firstChar = input.Substring(0, 1);
var restOfStmt = input.Substring(1);
var newFirst = "_" + firstChar.ToLower();
var output = newFirst + restOfStmt;
return output;
}
// this gets any tabs or spaces at the beginning of the line of code as a string,
// so as to preserve the indentation (and/or add deeper levels of indentation)
public static string GetCodeLineIndentation(string input)
{
var charArray = input.ToCharArray();
var sbPrefix = new StringBuilder();
foreach (var c in charArray)
{
// if it's a tab or a space, add it to the "prefix"
if (c == 9 || c == ' ')
{
sbPrefix.Append(c);
}
else
{
// get out as soon as we hit the first ascii character (those with a value up to 127)
break;
}
}
return sbPrefix.ToString();
}
static void Main(string[] args)
{
const string path = #"C:\pathToFile\Status.cs";
Console.WriteLine("Examining file: " + path);
if (!File.Exists(path))
{
Console.WriteLine("File does not exist: " + path);
throw new FileNotFoundException(path);
}
// Read the file.
var arrayOfLines = File.ReadAllLines(path);
// Convert to List<string>
var inputFileAsListOfStrings = new List<string>(arrayOfLines);
// See if there are any virtual properties.
var virtualProps = inputFileAsListOfStrings.Where(s => s.Contains("public virtual")).ToList();
// See if there are any "private set" strings.
var privateSets = inputFileAsListOfStrings.Where(s => s.Contains("private set")).ToList();
if (virtualProps.Count > 0)
{
Console.WriteLine("Found " + virtualProps.Count + " virtual properties in the class...");
}
if (privateSets.Count > 0)
{
Console.WriteLine("Found " + privateSets.Count + " private set statements in the class...");
}
// Get a list of names of the virtual properties
// (the 4th "word", i.e. index = 3, in the string, will be the property name,
// e.g. "public virtual string SomePropertyName"
var virtualPropNames = virtualProps.Select(vp => vp.Trim().Split(' ')).Select(words => words[3]).ToList();
if (virtualPropNames.Count() != virtualProps.Count())
{
throw new Exception("Error: the list of virtual property names does not equal the number of virtual property statements!");
}
// Find all instances of the virtual properties being initialized.
// By examining the overall file for instances of the virtual property name followed by an equal sign,
// we can identify those lines which are statements initializing the virtual property.
var initializeStatements = (from vpName in virtualPropNames
from stmt in inputFileAsListOfStrings
let stmtNoSpaces = stmt.Trim().Replace(" ", "")
where stmtNoSpaces.StartsWith(vpName + "=")
select stmt).ToList();
if (initializeStatements.Count() > 0)
{
Console.WriteLine("Found " + initializeStatements.Count + " initialize statements in the class...");
}
// now process the input based on the found strings and write the output
var outputFileAsListOfStrings = new List<string>();
foreach (var inputLineBeingProcessed in inputFileAsListOfStrings)
{
// is the input line one of the initialize statements identified previously?
// if so, rewrite the line.
// e.g.
// old line: StatusText = statusText;
// becomes: _statusText = statusText;
var isInitStmt = false;
foreach (var initStmt in initializeStatements)
{
if (inputLineBeingProcessed != initStmt) continue;
// we've found our statement; it is an initialize statement;
// now rewrite the format of the line as desired
var prefix = GetCodeLineIndentation(inputLineBeingProcessed);
var tabAndSpaceArray = new[] {' ', '\t'};
var inputLineWithoutPrefix = inputLineBeingProcessed.TrimStart(tabAndSpaceArray);
var outputLine = prefix + ConvertInitialCapitalToUnderscoreAndLowerCase(inputLineWithoutPrefix);
// write the line (preceded by its prefix) to the output file
outputFileAsListOfStrings.Add(outputLine);
Console.WriteLine("Rewrote INPUT: " + initStmt + " to OUTPUT: " + outputLine);
isInitStmt = true;
// we have now processed the input line; no need to loop through the initialize statements any further
break;
}
// if we've already determined the current input line is an initialize statement, no need to proceed further;
// go on to the next input line
if (isInitStmt)
continue;
// is the input line one of the "public virtual SomeType SomePropertyName" statements identified previously?
// if so, rewrite the single line as multiple lines of output.
// the input will look like this:
/*
public virtual SomeType SomePropertyName { get; set; }
*/
// first, we'll need a private variable which corresponds to the original statement in terms of name and type.
// what we'll do is, write the private field AFTER the public property, so as not to interfere with the XML
// comments above the "public virtual" statement.
// the output will be SIX LINES, as follows:
/*
public virtual SomeType SomePropertyName
{
get { return _somePropertyName; }
protected set { _someProperty = value; }
}
private SomeType _somePropertyName;
*/
var isPublicVirtualStatement = false;
foreach (var vp in virtualProps)
{
if (inputLineBeingProcessed != vp) continue;
// the input line being processed is a "public virtual" statement;
// convert it into the six line output format
var thisOutputList = new List<string>();
// first separate any indentation "prefix" that may exist (i.e. tabs and/or spaces),
// from the actual string of text representing the line of code
var prefix = GetCodeLineIndentation(inputLineBeingProcessed);
var tabAndSpaceArray = new[] { ' ', '\t' };
var inputLineWithoutPrefix = inputLineBeingProcessed.TrimStart(tabAndSpaceArray);
var originalVpStmt = inputLineWithoutPrefix.Split(' ');
// first output line (preceded by its original prefix)
var firstOutputLine = prefix +
originalVpStmt[0] + ' ' +
originalVpStmt[1] + ' ' +
originalVpStmt[2] + ' ' +
originalVpStmt[3];
thisOutputList.Add(firstOutputLine);
// second output line (indented to the same level as the original prefix)
thisOutputList.Add(prefix + "{");
// get field name from property name
var fieldName = ConvertInitialCapitalToUnderscoreAndLowerCase(originalVpStmt[3]);
// third output line (indented with the prefix, plus one more tab)
var thirdOutputLine = prefix + "\t" + "get { return " + fieldName + "; }";
thisOutputList.Add(thirdOutputLine);
// fourth output line (indented with the prefix, plus one more tab)
var fourthOutputLine = prefix + "\t" + "protected set { " + fieldName + " = value; }";
thisOutputList.Add(fourthOutputLine);
// fifth output line (indented to the same level as the first curly bracket)
thisOutputList.Add(prefix + "}");
// sixth output line (the "index 2" value of the original statement will be the string representing the .Net type)
// (indentation is the same as the "public virtual" statement above)
var sixthOutputLine = prefix +
"private" + ' ' +
originalVpStmt[2] + ' ' +
fieldName + ";";
thisOutputList.Add(sixthOutputLine);
// now write the six new lines to the master output list
outputFileAsListOfStrings.AddRange(thisOutputList);
isPublicVirtualStatement = true;
Console.WriteLine("Rewrote INPUT: " + inputLineBeingProcessed + " to OUTPUT: <multi-line block>");
break;
}
// if we've already determined the current input line is a "public virtual" statement, no need to proceed further;
// go on to the next input line
if (isPublicVirtualStatement)
continue;
// if we've gotten this far, the input statement is neither an "initialize" statement, nor a "public virtual" statement;
// So just write the output. Don't bother logging this as most lines will not be ones we'll process.
outputFileAsListOfStrings.Add(inputLineBeingProcessed);
}
// write the output file
var newPath = path.Replace(".cs", "-NEW.cs");
File.WriteAllLines(newPath, outputFileAsListOfStrings);
}
}
I am currently making an "app launcher" which reads a text file line by line. Each line is a path to a useful program somewhere else on my pc. A link label is automatically made for each path (i.e. each line) in the text file.
I would like the .Text property of the link label to be an abbreviated form of the path (i.e. just the file name, not the whole path). I have found out how to shorten the string in this way (so far so good !)
However, I would also like to store the full path somewhere - as this is what my linklabel will need to link to. In Javascript I could pretty much just add this property to linklabel like so: mylinklabel.fullpath=line; (where line is the current line as we read through the text file, and fullpath is my "custom" property that I would like to try and add to the link label. I guess it needs declaring, but I am not sure how.
Below is the part of my code which creates the form, reads the text file line by line and creates a link label for the path found on each line:
private void Form1_Load(object sender, EventArgs e) //on form load
{
//System.Console.WriteLine("hello!");
int counter = 0;
string line;
string filenameNoExtension;
string myfile = #"c:\\users\matt\desktop\file.txt";
//string filenameNoExtension = Path.GetFileNameWithoutExtension(myfile);
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(myfile);
while ((line = file.ReadLine()) != null)
{
//MessageBox.Show(line); //check whats on each line
LinkLabel mylinklabel = new LinkLabel();
filenameNoExtension = Path.GetFileNameWithoutExtension(line); //shortens the path to just the file name without extension
mylinklabel.Text = filenameNoExtension;
//string fullpath=line; //doesn't work
//mylinklabel.fullpath=line; //doesn't work
mylinklabel.Text = filenameNoExtension; //displays the shortened path
this.Controls.Add(mylinklabel);
mylinklabel.Location = new Point(0, 30 + counter * 30);
mylinklabel.AutoSize = true;
mylinklabel.VisitedLinkColor = System.Drawing.Color.White;
mylinklabel.LinkColor = System.Drawing.Color.White;
mylinklabel.Click += new System.EventHandler(LinkClick);
counter++;
}
file.Close();
}
So, how can I store a full path as a string inside the linklabel for use in my onclick function later on?
You could derive a new custom class or you could use a secondary data store for your additional info the easiest solution would be to use a dictionary.
dictonary<string,string> FilePaths = new dictonary<string,string>();
private void Form1_Load(object sender, EventArgs e) //on form load
{
...
FilePath[filenameNoExtension] = line;
}
You Can Access the Path
FilePath[mylinklabel.Tex]
One option you have is to have a method that truncates your string (and even adds "..."). You can then store the full path in the Tag property of the Linklabel. And here's an example of the first part (truncating the text).
public static string Truncate(this string s, int maxLength)
{
if (string.IsNullOrEmpty(s) || maxLength <= 0)
return string.Empty;
else if (s.Length > maxLength)
return s.Substring(0, maxLength) + "...";
else
return s;
}
Hope that helps some