I'm trying to create a program that encrypts files based on how Nazi Germany's Enigma machine worked, but without the flaw :P.
I have a function that gets a character at n point in a file, but when it returns a return character and I cout << it, it's like it hit enter twice.
IE if I loop cout-ing from i++ points in a file the individual lines in the terminal appear separated
by more returns
than one.
Here's the function:
char charN(string pathOf, int pointIn){
char r = NULL;
// NULL so I can tell when it doesn't return a character.
int sizeOf; //to store the found size of the file.
ifstream cf; //to store the Character Found.
ifstream siz; //used later to get the size of the file
siz.open(pathOf.c_str());
siz.seekg(0, std::ios::end);
sizeOf = siz.tellg(); // these get the length of the file and put it in sizeOf.
cf.open(pathOf.c_str());
if(cf.is_open() && pointIn < sizeOf){ //if not open, or if the character to get is farther out than the size of the file, let the function return the error condition: 'NULL'.
cf.seekg(pointIn); // move to the point in the file where the character should be, get it, and get out.
cf.get(r);
cf.close();
}
return r;
}
It works correctly if I use cout << '\n', but what's different about returns from a file and '\n'?
Or is there something else I'm missing?
I've been googling about but I can't find anything remotely similar to my problem, thanks in advance.
I'm using Code::Blocks 13.12 as my compiler if that matters.
Is this is on a windows machine? In windows new lines in text files are representing by \r\n.
\r = carriage return
\n = line feed
It's possible that you are couting each one separately and that the output buffer is creating a new line for each one.
I need to remove duplicates if
key = anything
but NOT
key=anything
the key can be anything too
e.g.
edit_home=home must be in place
while
edit_home = home or even other string must be removed IF edit_home is a duplicate
for all the lines of the document
thank you
p.s. clearer example:
one=you are
two=we are
three_why=8908908
one = good
two = fine
three_4 = best
three_why = win
from that list i only need to keep:
one=you are
two=we are
three_why=8908908
three_4 = best // because three_4 doesn't have a duplicate
I found a method to do it, but I would need a better search list support by regex or a plugin or a direct regex (which I don't know).
That is: I have two files to compare.
One has the full keys, the other has incomplete.
I merge in a new file all the keys from the first file with those ones of the second, in groups (because the keys are in groups e.g. many keys titled one, many titled two and so on...). Then I regex replace all the keys in the new file by
find (.*)(\s\=\s) replace with \1\=
So they all become key=anything
Then I replace everything after = with empty to isolate the keys.
Then remove the duplicates.
At this point I have trouble to do something like
^.*(^keyone\b|^keytwo\b|^keythree\b).*$
to find all those keys in the document I need. So from that I can select all and replace with the correct keys.
Why? Because in this example the keys are 3 only BUT indeed the keys are many and the find field breaks at a certain point.
How to do it right?
Update: I found Toolbucket plugin which allows to search for many strings, but another issue is that in addition to duplicate, I also have to remove the original.
That is, if I find 2 times the same key "one" I have to remove all the lines containing one.
Ctrl + F
Find tab
Find what: ^.*\S=\S.*$
Find All in Current Document
Copy result from result window to a new window (the list of Line 1: Line 2: Line 3: ...)
Ctrl + F
Replace tab
(the following will remove the leading "Line number:" from every line)
Find what: ^.*?\d:\s
Replace with: Empty
ok, after all that i wrote, one solution could be (therefore, once i have the merged keys)
(?m)^(.*)$(?=\r?\n^(?!\1).*(?s).*?\1)
with this i can mark/highlight all the duplicated keys :-) so then i can manage those only, removing them from the first list and adding what remains to the second file...
If someone has a solution with a direct regex will be really appreciated
Here is a commented UltraEdit script for this task.
// Note: This script does not work for large files as it loads the
// entire file content into very limited scripting memory for fast
// processing even with multiple GB of RAM installed.
if (UltraEdit.document.length > 0) // Is any file opened?
{
// Define environment for this script and select entire file content.
UltraEdit.insertMode();
UltraEdit.columnModeOff();
UltraEdit.activeDocument.selectAll();
// Determine line termination used currently in active file.
var sLineTerm = "\r\n";
if (typeof(UltraEdit.activeDocument.lineTerminator) == "number")
{
// The two lines below require UE v16.00 or UES v10.00 or later.
if (UltraEdit.activeDocument.lineTerminator == 1) sLineTerm = "\n";
else if (UltraEdit.activeDocument.lineTerminator == 2) sLineTerm = "\r";
}
else // This version of UE/UES does not offer line terminator property.
{
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\n"; // Not DOS, perhaps UNIX.
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\r"; // Also not UNIX, perhaps MAC.
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\r\n"; // No line terminator, use DOS.
}
}
}
}
// Get all lines of active file into an array of strings
// with each string being one line from active file.
var asLines = UltraEdit.activeDocument.selection.split(sLineTerm);
var nTotalLines = asLines.length;
// Process each line in the array.
for(var nCurrentLine = 0; nCurrentLine < asLines.length; nCurrentLine++)
{
// Skip all lines not containing or starting with an equal sign.
if (asLines[nCurrentLine].indexOf('=') < 1) continue;
// Get string left to equal sign with tabs/spaces trimmed.
var sKey = asLines[nCurrentLine].replace(/^[\t ]*([^\t =]+).*$/,"$1");
// Skip lines beginning with just tabs/spaces left to equal sign.
if (sKey.length == asLines[nCurrentLine].length) continue;
var_dump(sKey);
// Build the regular expression for the search in all other lines.
var rRegSearch = new RegExp("^[\\t ]*"+sKey+"[\\t ]*=","g");
// Ceck all remaining lines for a line also starting with
// this key string case-sensitive with left to an equal sign.
var nLineCompare = nCurrentLine + 1;
while(nLineCompare < asLines.length)
{
// Does this line also has this key left to equal
// sign with or without surrounding spaces/tabs?
if (asLines[nLineCompare].search(rRegSearch) < 0)
{
nLineCompare++; // No, continue on next line.
}
else // Yes, remove this line from array.
{
asLines.splice(nLineCompare,1);
}
}
}
// Was any line removed from the array?
if (nTotalLines == asLines.length)
{
UltraEdit.activeDocument.top(); // Cancel the selection.
UltraEdit.messageBox("Nothing found to remove!");
}
else
{
// If version of UE/UES supports direct write to clipboard, use
// user clipboard 9 to paste the lines into file with overwritting
// everything as this is much faster than using write command in
// older versions of UE/UES.
if (typeof(UltraEdit.clipboardContent) == "string")
{
var nActiveClipboard = UltraEdit.clipboardIdx;
UltraEdit.selectClipboard(9);
UltraEdit.clipboardContent = asLines.join(sLineTerm);
UltraEdit.activeDocument.paste();
UltraEdit.clearClipboard();
UltraEdit.selectClipboard(nActiveClipboard);
}
else UltraEdit.activeDocument.write(asLines.join(sLineTerm));
var nRemoved = nTotalLines - asLines.length;
UltraEdit.activeDocument.top();
UltraEdit.messageBox("Removed " + nRemoved + " line" + ((nRemoved != 1) ? "s" : "") + " on updated file.");
}
}
Copy this code and paste it into a new ASCII file using DOS line terminators in UltraEdit.
Next use command File - Save As to save the script file for example with name RemoveDuplicateKeys.js into %AppData%\IDMComp\UltraEdit\MyScripts or wherever you want to have saved your UltraEdit scripts.
Open Scripting - Scripts and add the just saved UltraEdit script to the list of scripts. You can enter a description for this script, too.
Open the file with the list, or make this file active if it is already opened in UltraEdit.
Run the script by clicking on it in menu Scripting, or by opening Views - Views/Lists - Script List and double clicking on the script.
I've written a program in F90 which reads in a few input arrays from text files and then combines them through a function to a single output file. One of the input files is named for the day the data was collected using MMDDYY.tuvr and the output file is then named MMDDYY.fxi . I'd like to be able to input the MMDDYY of the data in the command line when running the program instead of having to manually change the code and compile each time, which is why I'm attempting to use getarg, but I cannot seem to make it work properly. The code im attempting to use is listed below (just shows the get arg and the open commands and not the entire program since this is where I'm having trouble):
CHARACTER(len=20) :: arg, tuvrname, fxiname
CALL getarg(1, arg)
IF(LEN_TRIM(arg) == 0) THEN
print*,'No date provided'
STOP
ELSE
tuvrname = TRIM(arg)'.tuvr'
fxiname = TRIM(arg).'fxi'
ENDIF
OPEN(1, file = tuvrname, status='old', action='read')
....
OPEN(4, file = fxiname, status='replace', action='write')
I also tried just using two separate getarg commands and entering MMDDDYY.tuvr MMDDYY.fxi in the command line and the program ran, but it could not seem to find my TUVR file as the output was empty.
I am not really experienced in using getarg. I use get_command_argument from Fortran 2003. I think you just forgot to use // to concatenate the strings.
CHARACTER(len=20) :: arg, tuvrname, fxiname
CALL getarg(1, arg)
IF(LEN_TRIM(arg) == 0) THEN
print*,'No date provided'
STOP
ELSE
tuvrname = TRIM(arg)//'.tuvr'
fxiname = TRIM(arg)//'.fxi'
ENDIF
print *, tuvrname, fxiname
end
or
CHARACTER(len=20) :: arg, tuvrname, fxiname
if (command_argument_count()<1) then
stop "Provide the file name."
end if
CALL get_command_argument(1, value=arg)
tuvrname = TRIM(arg)//'.tuvr'
fxiname = TRIM(arg)//'.fxi'
print *, tuvrname, fxiname
end
I apologize if you know nothing about Python, however, the following snippet should be very readable to anyone. The only trick to watch out for - indexing a list with [-1] gives you the last element if there is one, or raises an exception.
>>> fileName = 'TheFileName.Something.xMl'
>>> fileNameList = fileName.split('.')
>>> assert(len(fileNameList) > 1) # Must have at least one period in it
>>> assert(fileNameList[-1].lower() == 'xml')
>>> fileNameList[-1] = 'bak'
>>> fileName = '.'.join(fileNameList)
>>> print(fileName)
TheFileName.Something.bak
I need to convert this logic into C++ (the language I am actually using, but so far suck at) function with the following signature: void PopulateBackupFileNameOrDie(CAtlString& strBackupFileName, CAtlString& strXmlFileName);. Here strXmlFileName is "input", strBackupFileName is "output" (should I reverse the oprder of the two?). The tricky part is that (correct me if I am wrong) I am working with a Unicode string, so looking for these characters: .xmlXML is not as straight-forward. Latest Python does not have these issues because '.' and "." are both Unicode strings (not a "char" type) of length 1, both contain just a dot.
Notice that the return type is void - do not worry much about it. I do not want to bore you with details of how we communicate an error back to the user. In my Python example I just used an assert. You can do something like that or just include a comment such as // ERROR: [REASON].
Please ask if something is not clear. Suggestions to use std::string, etc. instead of CAtlString for function parameters are not what I am looking for. You may convert them inside the function if you have to, but I would prefer not mixing different string types in one function. I am compiling this C++ on Windows, using VS2010. This implies that I WILL NOT install BOOST, QTString or other libraries which are not available out of the box. Stealing a boost or other header to enable some magic is also not the right solution.
Thanks.
If you're using ATL why not just use CAtlString's methods?
CAtlString filename = _T("TheFileName.Something.xMl");
//search for '.' from the end
int dotIdx = filename.ReverseFind( _T('.') );
if( dotIdx != -1 ) {
//extract the file extension
CAtlString ext = filename.Right( filename.GetLength() - dotIdx );
if( ext.CompareNoCase( _T(".xml" ) ) == 0 ) {
filename.Delete( dotIdx, ext.GetLength() ); //remove extension
filename += _T(".bak");
}
}
I didn't split the string as your code does because that's a bit more work in C++ for really no gain (it's slower, and for this task you really don't need to do it).
string filename = "TheFileName.Something.xMl";
size_t pos = filename.rfind('.');
assert(pos > 0 && pos == filename.length()-4); // the -4 here is for length of ".xml"
for(size_t i = pos+1; i < filename.length(); ++i)
filename[i] = tolower(filename[i]);
assert(filename.substr(pos+1) == "xml");
filename = filename.substr(0,pos+1) + "bak";
std::cout << filename << std::endl;
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I'm trying to parse an INI file using C++. Any tips on what is the best way to achieve this? Should I use the Windows API tools for INI file processing (with which I am totally unfamiliar), an open-source solution or attempt to parse it manually?
You can use the Windows API functions, such as GetPrivateProfileString() and GetPrivateProfileInt().
If you need a cross-platform solution, try Boost's Program Options library.
I have never parsed ini files, so I can't be too specific on this issue.
But i have one advice:
Don't reinvent the wheel as long as an existing one meets your requirements
http://en.wikipedia.org/wiki/INI_file#Accessing_INI_files
http://sdl-cfg.sourceforge.net/
http://sourceforge.net/projects/libini/
http://www.codeproject.com/KB/files/config-file-parser.aspx
Good luck :)
If you are already using Qt
QSettings my_settings("filename.ini", QSettings::IniFormat);
Then read a value
my_settings.value("GroupName/ValueName", <<DEFAULT_VAL>>).toInt()
There are a bunch of other converter that convert your INI values into both standard types and Qt types. See Qt documentation on QSettings for more information.
I use SimpleIni. It's cross-platform.
this question is a bit old, but I will post my answer. I have tested various INI classes (you can see them on my website) and I also use simpleIni because I want to work with INI files on both windows and winCE.
Window's GetPrivateProfileString() works only with the registry on winCE.
It is very easy to read with simpleIni. Here is an example:
#include "SimpleIni\SimpleIni.h"
CSimpleIniA ini;
ini.SetUnicode();
ini.LoadFile(FileName);
const char * pVal = ini.GetValue(section, entry, DefaultStr);
inih is a simple ini parser written in C, it comes with a C++ wrapper too. Example usage:
#include "INIReader.h"
INIReader reader("test.ini");
std::cout << "version="
<< reader.GetInteger("protocol", "version", -1) << ", name="
<< reader.Get("user", "name", "UNKNOWN") << ", active="
<< reader.GetBoolean("user", "active", true) << "\n";
The author has also a list of existing libraries here.
Have you tried libconfig; very JSON-like syntax. I prefer it over XML configuration files.
I ended up using inipp which is not mentioned in this thread.
https://github.com/mcmtroffaes/inipp
Was a MIT licensed header only implementation which was simple enough to add to a project and 4 lines to use.
If you are interested in platform portability, you can also try Boost.PropertyTree. It supports ini as persistancy format, though the property tree my be 1 level deep only.
Unless you plan on making the app cross-platform, using the Windows API calls would be the best way to go. Just ignore the note in the API documentation about being provided only for 16-bit app compatibility.
I know this question is very old, but I came upon it because I needed something cross platform for linux, win32... I wrote the function below, it is a single function that can parse INI files, hopefully others will find it useful.
rules & caveats:
buf to parse must be a NULL terminated string. Load your ini file into a char array string and call this function to parse it.
section names must have [] brackets around them, such as this [MySection], also values and sections must begin on a line without leading spaces. It will parse files with Windows \r\n or with Linux \n line endings. Comments should use # or // and begin at the top of the file, no comments should be mixed with INI entry data. Quotes and ticks are trimmed from both ends of the return string. Spaces are only trimmed if they are outside of the quote. Strings are not required to have quotes, and whitespaces are trimmed if quotes are missing. You can also extract numbers or other data, for example if you have a float just perform a atof(ret) on the ret buffer.
// -----note: no escape is nessesary for inner quotes or ticks-----
// -----------------------------example----------------------------
// [Entry2]
// Alignment = 1
// LightLvl=128
// Library = 5555
// StrValA = Inner "quoted" or 'quoted' strings are ok to use
// StrValB = "This a "quoted" or 'quoted' String Value"
// StrValC = 'This a "tick" or 'tick' String Value'
// StrValD = "Missing quote at end will still work
// StrValE = This is another "quote" example
// StrValF = " Spaces inside the quote are preserved "
// StrValG = This works too and spaces are trimmed away
// StrValH =
// ----------------------------------------------------------------
//12oClocker super lean and mean INI file parser (with section support)
//set section to 0 to disable section support
//returns TRUE if we were able to extract a string into ret value
//NextSection is a char* pointer, will be set to zero if no next section is found
//will be set to pointer of next section if it was found.
//use it like this... char* NextSection = 0; GrabIniValue(X,X,X,X,X,&NextSection);
//buf is data to parse, ret is the user supplied return buffer
BOOL GrabIniValue(char* buf, const char* section, const char* valname, char* ret, int retbuflen, char** NextSection)
{
if(!buf){*ret=0; return FALSE;}
char* s = buf; //search starts at "s" pointer
char* e = 0; //end of section pointer
//find section
if(section)
{
int L = strlen(section);
SearchAgain1:
s = strstr(s,section); if(!s){*ret=0; return FALSE;} //find section
if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain1;} //section must be at begining of a line!
s+=L; //found section, skip past section name
while(*s!='\n'){s++;} s++; //spin until next line, s is now begining of section data
e = strstr(s,"\n["); //find begining of next section or end of file
if(e){*e=0;} //if we found begining of next section, null the \n so we don't search past section
if(NextSection) //user passed in a NextSection pointer
{ if(e){*NextSection=(e+1);}else{*NextSection=0;} } //set pointer to next section
}
//restore char at end of section, ret=empty_string, return FALSE
#define RESTORE_E if(e){*e='\n';}
#define SAFE_RETURN RESTORE_E; (*ret)=0; return FALSE
//find valname
int L = strlen(valname);
SearchAgain2:
s = strstr(s,valname); if(!s){SAFE_RETURN;} //find valname
if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain2;} //valname must be at begining of a line!
s+=L; //found valname match, skip past it
while(*s==' ' || *s == '\t'){s++;} //skip spaces and tabs
if(!(*s)){SAFE_RETURN;} //if NULL encounted do safe return
if(*s != '='){goto SearchAgain2;} //no equal sign found after valname, search again
s++; //skip past the equal sign
while(*s==' ' || *s=='\t'){s++;} //skip spaces and tabs
while(*s=='\"' || *s=='\''){s++;} //skip past quotes and ticks
if(!(*s)){SAFE_RETURN;} //if NULL encounted do safe return
char* E = s; //s is now the begining of the valname data
while(*E!='\r' && *E!='\n' && *E!=0){E++;} E--; //find end of line or end of string, then backup 1 char
while(E > s && (*E==' ' || *E=='\t')){E--;} //move backwards past spaces and tabs
while(E > s && (*E=='\"' || *E=='\'')){E--;} //move backwards past quotes and ticks
L = E-s+1; //length of string to extract NOT including NULL
if(L<1 || L+1 > retbuflen){SAFE_RETURN;} //empty string or buffer size too small
strncpy(ret,s,L); //copy the string
ret[L]=0; //null last char on return buffer
RESTORE_E;
return TRUE;
#undef RESTORE_E
#undef SAFE_RETURN
}
How to use... example....
char sFileData[] = "[MySection]\r\n"
"MyValue1 = 123\r\n"
"MyValue2 = 456\r\n"
"MyValue3 = 789\r\n"
"\r\n"
"[MySection]\r\n"
"MyValue1 = Hello1\r\n"
"MyValue2 = Hello2\r\n"
"MyValue3 = Hello3\r\n"
"\r\n";
char str[256];
char* sSec = sFileData;
char secName[] = "[MySection]"; //we support sections with same name
while(sSec)//while we have a valid sNextSec
{
//print values of the sections
char* next=0;//in case we dont have any sucessful grabs
if(GrabIniValue(sSec,secName,"MyValue1",str,sizeof(str),&next)) { printf("MyValue1 = [%s]\n",str); }
if(GrabIniValue(sSec,secName,"MyValue2",str,sizeof(str),0)) { printf("MyValue2 = [%s]\n",str); }
if(GrabIniValue(sSec,secName,"MyValue3",str,sizeof(str),0)) { printf("MyValue3 = [%s]\n",str); }
printf("\n");
sSec = next; //parse next section, next will be null if no more sections to parse
}
Maybe a late answer..But, worth knowing options..If you need a cross-platform solution , definitely you can try GLIB,, its interesting.. (https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)