Edit file content - file-io

In Form1 I have 2 TextBoxes(surname and name). When I push the "register" button I write them into a file through TextWriter. Every line contains surname and name, So there are 2 fields per line.
In Form2 I want to edit them by asking a parameter. For example in Form2 I have one TextBox. If the surname I type into the TextBox is equal to one from my file, i want to show surname and name in correct TextBoxes in Form1, and after editing surname or name I want to overwrite previous line in the correct place by pushing the "register" button.
Thanks to user Medinoc I write the file like this:
ref class MyClass
{
public:
String^ cognome;
String^ nome;
};
//...
List<MyClass^>^ primo = gcnew List<MyClass^>();
//...
MyClass^ myObj = gcnew MyClass();
myObj->cognome = textBox1->Text;
myObj->nome = textBox2->Text;
primo->Add(myObj);
//...
TextWriter ^tw = gcnew StreamWriter(L"primoAnno.txt", true);
for each(MyClass^ obj in primo)
{
//You can use any character or string as separator,
//as long as it's not supposed to appear in the strings.
//Here, I used pipes.
tw->Write(obj->cognome);
tw->Write(L"|");
tw->Write(obj->nome);
}
tw->Close();
READ
MyClass^ ParseMyClass(String^ line)
{
array<String^>^ splitString = line->Split(L'|');
MyClass^ myObj = gcnew MyClass();
myObj->cognome = splitString[0];
myObj->nome = splitString[1];
return myObj;
}
Hope I was clear enough. I'm not english.
Thanks in advance!!

It's still classic text file editing behavior:
What you need is a function to search for a particular line in the file; and another function to modify a particular line. That one will be similar to the deleting code.
Find:
MyClass^ FindMyClass(String^ surnameToFind)
{
MyClass^ found = nullptr;
TextReader^ tr = gcnew StreamReader(L"primoAnno.txt");
String^ line;
while(found == nullptr && (line=tr->ReadLine()) != nullptr)
{
MyClass^ obj = ParseMyClass(line);
if(obj->cognome == surnameToFind)
found = surnameToFind;
}
tr->Close();
}
Update:
MyClass^ objToUpdate = gcnew MyClass;
objToUpdate->cognome = textBox1->Text;
objToUpdate->nome = textBox2->Text;
TextWriter^ tw = gcnew StreamWriter(L"primoAnno2.txt", true);
TextReader^ tr = gcnew StreamReader(L"primoAnno.txt");
String^ line;
bool updated = false;
while((line=tr->ReadLine()) != nullptr)
{
MyClass^ obj = ParseMyClass(line);
if(obj->cognome == objToUpdate->cognome)
{
line = objToUpdate->cognome + L"|" + objToUpdate->nome;
updated = true;
}
tw->WriteLine(line);
}
//If the surname was not in the file at all, add it.
if(!updated)
{
line = objToUpdate->cognome + L"|" + objToUpdate->nome;
tw->WriteLine(line);
}
tr->Close();
tw->Close();
File::Delete(L"primoAnno.txt");
File::Move(L"primoAnno2.txt", L"primoAnno.txt");

Related

Error "Out of segment space" in VMEmulator cause by a getter mwthod in Jack

I am doing a project for nand2tetris. We write a program in Jack and test it on VMEmulator. The class looks like this:
class List {
field int data;
field List next;
/* Creates a new List object. */
constructor List new(int car, List cdr) {
let data = car;
let next = cdr;
return this;
}
/* Disposes this List by recursively disposing its tail. */
method void dispose() {
if (~(next = null)) {
do next.dispose();
}
// Use an OS routine to recycle the memory held by this object.
do Memory.deAlloc(this);
return;
}
/* Prints the list*/
method void print() {
do Output.printString(" -> ");
do Output.printInt(data);
if (~(next = null)) {
do next.print();
}
return;
}
/* Inserts the argument in the right position of the list (ascending order)*/
method void insertInOrder(int ins){
var List prev, curr, insert;
let prev = this;
let curr = prev.getnext();
while (ins > prev.getdata()){
if (ins < curr.getdata()){
let insert = List.new(ins, curr);
do prev.setnext(insert);
}
else{
let prev = prev.getnext();
let curr = prev.getnext();
}
}
return;
}
/* Searches the argument in the list, if found, it returns the corresponding List object*/
method List find(int toFind){
var List temp;
var List equal;
var boolean found;
let temp = this;
let found = false;
while (~(next = null)){
if(toFind = temp.getdata()){
let equal = temp;
let found = true;
}
let temp = temp.getnext();
}
if (found){
return equal;
}
else{
return null;
}
}
method List getnext(){
return next;
}
method void setnext(List object){
let next = object;
return;
}
method int getdata(){
return data;
}
}
It has one private variable data and a pointer next. So I wrote getter and setter method to return those values. Other methods are fine only the getdata()method is incorrect. When it runs through the VMEmulator, it shows the error Out of segment space in List.getdata.3. This shows in the VMEmulator.
0function List.getdata0
1push argument0
2pop pointer0
3push this 0
4return
the error is at the 4th line return. When I change the Jack code, the same error is still at the 4th line.
What exactly is the problem in my getter method?
When you run a VM program on the VMEmulator you must first manually set the pointers to the various segments, otherwise you may get an "Out of segment space" error.
To understand the necessary settings, look at what the corresponding .tst file does. An alternative method is to insert the proposed code inside a function, since the function call automatically makes this type of setting.
You can get this error when you try to access member data of an object which is not constructed. Could it be that the List cdr in the constructor was not properly constructed?

Why is this method throwing a null pointer exception?

I'm attempting to write a class to create a prefix tree (or trie) with an addWord method that takes in a string as a parameter and stores each character in it's appropriate place in the tree.
However, I keep getting a NullPointerException in the line of my first if statement (indicated below). Can anyone help me understand what's causing this? Thank you in advance!
public class PrefixTree {
private Node root;
public PrefixTree () {
root = new Node();
}
public void addWord(String word) {
int length = word.length();
char currentCharacter = word.charAt(0);
Node currentNode = root;
//Essentially this is saying "for each character in the string..."
for(int i=0; i<length; i++){
currentCharacter= word.charAt(i);
//if the children array of parent node does not contain the current character
//create a new node and add it to the parent array.
//HERE IS WHERE THE EXCEPTION IS BEING THROWN
if(currentNode.children[currentCharacter - 'a'] == null) {
Node newNode = new Node();
//set the node character value equal to the current character
newNode.c=currentCharacter;
//add the new node to the child array of its parent node
currentNode.children[currentCharacter - 'a']= newNode;
//if this is the last character in the word, change the endWord value to true
if( i == length-1) {
newNode.endWord = true;
//stores the complete string in its ending node
newNode.fullWord = word;
}
//set current node equal to the new node created and repeat the process
currentNode = newNode;
}
}
}
private class Node {
public boolean endWord;
public char c;
public Node[] children;
public String fullWord;
public Node(){
c = '0';
endWord = false;
Node[] children = new Node[26];
//Stores the complete string of a word ending w/ this node to make life easier later
String fullWord = null;
}
}
public static void main(String [] args){
PrefixTree test = new PrefixTree();
test.addWord("test");
}
}
Because you're assigning to local variables in Node's constructor. Change to this:
public Node(){
c = '0';
endWord = false;
this.children = new Node[26];
//Stores the complete string of a word ending w/ this node to make life easier later
this.fullWord = null;
}

Why can't I get input from the ifstream?

I am trying to read in a text file for a maze program. The input is something like:
10 10
OO+E+OO+++
O++O+O+OOO
OOOOOO+O+O
+++++O++OO
OOO+OOO+O+
O+O+O+++O+
O+O+OOO+OO
++O+++O++O
O+OOOOO++O
O+O++O+OOO
When the user click on the open button, this opens a open file dialog box
{
openFileDialog1->InitialDirectory = "C:\Desktop;";
openFileDialog1->Filter = "Maze files (*.DAT)|*.DAT";
if (openFileDialog1->ShowDialog() == ::DialogResult::OK)
{
char filename[1024];
for (int i = 0; i < openFileDialog1->FileName->Length; i++)
{
filename[i] = openFileDialog1->FileName[i];
}
ifstream ifs;
ifs.open(filename); // NULL terminate this
maze = new Maze( panel1, ifs);
ifs.close();
}
}
the following is the maze constructor
Maze::Maze( Panel ^ drawingPanel, ifstream & ifs )
{
try
{
valid = false;
ifs >> width >> height;
int temp = width;
drawingPanel->Size.Width = width;
drawingPanel->Size.Height = height;
for (int i = 0; i < height; i++) // height is always nothing
for (int j = 0; j < width; j++)
{
if (orig[j][i] == DEADEND ||
orig[j][i] == OPEN ||
orig[j][i] == EXIT )
ifs >> orig[j][i]; // NULLS????
else
throw 'D'; // i had to throw something....so i threw the D /* make a slit class and throw the D there? slit.fill(D); */
}
// this should be last
panel = drawingPanel;
valid = true;
}
catch (...)
{
valid = false;
MessageBox::Show( "Not a proper maze file!" );
}
}
when the program runs: ifs >> width >> height width and height do not get set correctly.
I have searched this site for this problem and have not been able to find anything that has helped. Sorry for my inexperience, any help is greatly appreciated.
You'e program very ugly : don't know if you're programming in C or C++ or C++/CLI, or try to mix the 3...
Because you use Windows Form projet, i will give you a .Net solution for read a file, it's not the better solution but this does not mix things.
First for read the file, on a first window :
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
openFileDialog1->Filter = "Maze Files (*.dat) | *.dat";
if (openFileDialog1->ShowDialog() == ::DialogResult::OK)
{
String ^fileName = openFileDialog1->FileName;
IO::StreamReader ^myMazeFile = gcnew IO::StreamReader(fileName);
String ^content = myMazeFile->ReadToEnd();
richTextBox1->Text = content;
myMazeFile->Close();
// display button for open second form wich draw maze
button2->Visible = true;
}
}
now we have our file content, so we pass it to a second form who will draw the maze :
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e)
{
String ^content = richTextBox1->Text;
Maze ^frm = gcnew Maze(content);
frm->Show();
}
Second window, create overload constructor :
Maze(String ^contentMap)
{
InitializeComponent();
String ^dimension = getWords(contentMap, 2);
array<String ^> ^coordsString = dimension->Split(gcnew array<Char> {' '});
m_width = Convert::ToInt32(coordsString[0]);
m_height = Convert::ToInt32(coordsString[1]);
panel1->Width = m_width;
panel1->Height = m_height;
}
getWords method :
String ^getWords(String ^input, int numWords)
{
try
{
int words = numWords;
for (int i = 0; i < input->Length; ++i)
{
if (input[i] == ' ' ||input[i] == '\n')
words--;
if (words == 0)
{
return input->Substring(0, i);
}
}
}
catch (Exception ^ex)
{
// ...
}
return String::Empty;
}
You have your dimension in full .Net (private member m_width and m_height).

How do i copy to a List?

I have this code in CLI
List<Codec^> ^GetCodecs()
{
List<Codec^> ^l = gcnew List<Codec^>;
bool KeepLooping = Encoder_MoveToFirstCodec();
while (KeepLooping)
{
Codec ^codec = gcnew Codec(); // here... and that call encoder_init many times... which call register codec many times... which is a mass...
codec->Name = gcnew String(Encoder_GetCurrentCodecName());
codec->Type = Encoder_GetCurrentCodecType();
char pix_fmts[200]; // array of 200 is probably enough
int actual_pix_fmts_sz = Encoder_GetCurrentCodecPixFmts( pix_fmts , 200 );
for (int i = 0 ; i < actual_pix_fmts_sz ; i++)
{
//copy from pix_fmts to the :List
codec->SupportedPixelFormats->Add(pix_fmts[i]);
}
This is the Encoder_GetCurrentCodecPixFmts function in C:
int Encoder_GetCurrentCodecPixFmts( char *outbuf , int buf_sz )
{
int i=0;
while ( (i<buf_sz) && (codec->pix_fmts[i]!=-1) )
{
outbuf[i] = codec->pix_fmts[i];
i++;
}
return i;
}
This is a new class i did:
#pragma once
using namespace System;
using namespace System::Collections::Generic;
public ref class Codec
{
public:
String^ Name;
int ID; // this is the index
int Type; // this is the type
List<int> ^SupportedPixelFormats;
Codec(void)
{
SupportedPixelFormats = gcnew List<int>;
// do nothing in the constructor;
}
};
Which contain also the: SupportedPixelFormats
The constructor in this new class should be empty but i needed somewhere to make an instance for the List make a NEW for the List.
Now in the C++ i need to transfer from pix_fmts char array to codec->Supported
Or to copy from pix_fmts to the :List
So i did as above:
codec->SupportedPixelFormats->Add(pix_fmts[i]);
But i'm not sure if this the meaning of copy.
Is that right what i did ?
It works, it's a kind of a deep copy. What makes you think it doesn't work? Do the results turn out wrong? If they do, put a breakpoint in there and try to get what is wrong.
Instead of copying one by one perhaps you can use the Enumerable::ToList extension method.
I hope this helped you.

StyledDocument adding extra count to indexof for each line of file

I have a strange problem (at least it appears that way) that when searching for a string in a textPane, I get an extra index for each line number that is searched and returned when using StyledDoc verses just getting the text from a textPane. I get the same text from the same pane, it's just that one is from the plain text the other is from the styled doc. Am I missing something here. I'll try to list as many of the changes between the two versions I am working with.
The plain text version:
public int displayXMLFile(String path, int target){
InputStreamReader inputStream;
FileInputStream fileStream;
BufferedReader buffReader;
if(target == 1){
try{
File file = new File(path);
fileStream = new FileInputStream(file);
inputStream = new InputStreamReader(fileStream,"UTF-8");
buffReader = new BufferedReader(inputStream);
StringBuffer content = new StringBuffer("");
String line = "";
while((line = buffReader.readLine())!=null){
content.append(line+"\n");
}
buffReader.close();
xhw.txtDisplay_1.setText(content.toString());
}
catch(Exception e){
e.printStackTrace();
return -1;
}
}
}
verses the Styled Doc (without the styles applied)
protected void openFile(String path, StyledDocument sDoc, int target)
throws BadLocationException {
FileInputStream fileStream;
String file;
if(target == 1){
file = "Openning First File";
} else {
file = "Openning Second File";
}
try {
fileStream = new FileInputStream(path);
// Get the object of DataInputStream
//DataInputStream in = new DataInputStream(fileStream);
ProgressMonitorInputStream in = new ProgressMonitorInputStream(
xw.getContentPane(), file, fileStream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
sDoc.insertString(sDoc.getLength(), strLine + "\n", sDoc.getStyle("regular"));
xw.updateProgress(target);
}
//Close the input stream
in.close();
} catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
This is how I search:
public int searchText(int sPos, int target) throws BadLocationException{
String search = xhw.textSearch.getText();
String contents;
JTextPane searchPane;
if(target == 1){
searchPane = xhw.txtDisplay_1;
} else {
searchPane = xhw.txtDisplay_2;
}
if(xhw.textSearch.getText().isEmpty()){
xhw.displayDialog("Nothing to search for");
highlight(searchPane, null, 0,0);
} else {
contents = searchPane.getText();
// Search for the desired string starting at cursor position
int newPos = contents.indexOf( search, sPos );
// cycle cursor to beginning of doc window
if (newPos == -1 && sPos > 0){
sPos = 0;
newPos = contents.indexOf( search, sPos );
}
if ( newPos >= 0 ) {
// Select occurrence if found
highlight(searchPane, contents, newPos, target);
sPos = newPos + search.length()+1;
} else {
xhw.displayDialog("\"" + search + "\"" + " was not found in File " + target);
}
}
return sPos;
}
The sample file:
<?xml version="1.0" encoding="UTF-8"?>
<AlternateDepartureRoutes>
<AlternateDepartureRoute>
<AdrName>BOIRR</AdrName>
<AdrRouteAlpha>..BROPH..</AdrRouteAlpha>
<TransitionFix>
<FixName>BROPH</FixName>
</TransitionFix>
</AlternateDepartureRoute>
<AlternateDepartureRoute>
</AlternateDepartureRoutes>
And my highlighter:
public void highlight(JTextPane tPane, String text, int position, int target) throws BadLocationException {
Highlighter highlighter = new DefaultHighlighter();
Highlighter.HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(Color.LIGHT_GRAY);
tPane.setHighlighter(highlighter);
String searchText = xhw.textSearch.getText();
String document = tPane.getText();
int startOfSString = document.indexOf(searchText,position);
if(startOfSString >= 0){
int endOfSString = startOfSString + searchText.length();
highlighter.addHighlight(startOfSString, endOfSString, painter);
tPane.setCaretPosition(endOfSString);
int caretPos = tPane.getCaretPosition();
javax.swing.text.Element root = tPane.getDocument().getDefaultRootElement();
int lineNum = root.getElementIndex(caretPos) +1;
if (target == 1){
xhw.txtLineNum1.setText(Integer.toString(lineNum));
} else if (target == 2){
xhw.txtLineNum2.setText(Integer.toString(lineNum));
} else {
xhw.txtLineNum1.setText(null);
xhw.txtLineNum2.setText(null);
}
} else {
highlighter.removeAllHighlights();
}
}
When I do a search for Alt with the indexof() I get 40 for the plain text (which is what it should return) and 41 when searching with the styled doc. And for each additional line that Alt appears on I get and extra index (so that the indexof() call returns 2 more then needed in line 3). This happens for every additional line that it finds. Am I missing something obvious? (If I need to push this to a smaller single class to make it easier to check I can do this later when I have some more time).
Thanks in advance...
If you are on Windows, then the TextComponent text (searchPane.getText()) can contain carriage-return+newline characters (\r\n), but the TextComponent's Styled Document (sSearchPane.getText(0, sSearchPane.getLength())) contains only newline characters (\n). That's why your newPos is always larger than newPosS by the number of newlines at that point. To fix this, in your search function you can change:
contents = searchPane.getText();
to:
contents = searchPane.getText().replaceAll("\r\n","\n");
That way the search occurs with the same indices that the Styled Document is using.
OK I have found a solution (basicly). I approached this from the aspect that I am getting text from the same text componet in two different ways...
String search = xw.textSearch.getText();
String contents;
String contentsS;
JTextPane searchPane;
StyledDocument sSearchPane;
searchPane = xw.txtDisplay_left;
sSearchPane = xw.txtDisplay_left.getStyledDocument();
contents = searchPane.getText();
contentsS = sSearchPane.getText(0, sSearchPane.getLength());
// Search for the desired string starting at cursor position
int newPos = contents.indexOf( search, sPos );
int newPosS = contentsS.indexOf(search, sPos);
So when comparing the two variables "newPos" & "newPosS", newPos retruned 1 more then newPosS for each line that the search string was found on. So when looking at the sample file and searching for "Alt" the first instance is found on line 2. "newPos" returns 41 and "newPosS returns 40 (which then highlights the correct text). The next occurance (which is found in line 3) "newPos" returns 71 and "newPosS" returns 69. As you can see, every new line increases the count by the line number the occurance begins in. I would suspect that there is an extra character being added in for each new line from the textPane that is not present in the StyledDoc.
I'm sure there is a reasonable explaination but I don't have it at this time.