I have a C++ code that searches for every directory containing the word 'disk' inside the directory /dev/ (im on a mac) which is where all USB drives are, but when I'm doing QRegExp("disk*") it can't find any, but when I do 'mount' in Terminal, i can find my USB named disk1s5. Why can't I find it with QRegExp?
#ifdef __APPLE__
DIR *dir = NULL;
dirent *search = NULL;
dir = opendir("/dev/");
if (dir != NULL)
{
while ((search = readdir(dir)) != NULL)
{
QRegExp exp("disk*");
exp.setPatternSyntax(QRegExp::Wildcard);
exp.setCaseSensitivity(Qt::CaseInsensitive);
if (exp.exactMatch(search->d_name))
{
return 0;
} else {
return 2;
}
}
} else {
return 1;
}
endif
It seems you're confusing globbing (wildcards used in shells etc) and regular expressions. But they are not the same.
In regular expressions, * means the preceding item appears zero or more times. As such, disk* matches the strings dis, disk, diskk, diskkk and so on.
If you want to check for disk followed by anything (including nothing), you must use disk.* where . means any character so .* means any character appearing zero or more times. This corresponds exactly to the globbing pattern disk*.
Depending on your needs, you could also use disk.+ to match for disk followed by any character appearing one or more times (which, compared to disk.*, does not match the string disk itself).
I strongly suggest you read the documentation to understand how regular expressions really work.
If you just want to find all disk* dirs from /dev and you are using Qt, you can do it like this:
QDir dir("/dev");
QStringList nameFilter = QStringList() << "disk*";
QStringList disks = dir.entryList(nameFilter, QDir::System|QDir::Dirs);
foreach (QString d, disks)
qDebug() << d;
Related
I have this function to return whether the specified directory exists:
double directory_exists(char *pathname)
{
struct stat sb;
return (stat(pathname,&sb) == 0 &&
S_ISDIR(sb.st_mode));
}
However, if the last character the user typed is a slash ("\" on Windows or "/" on Mac / Linux) I'd like to remove that character from the pathname and store that value in a new variable and use that variable in stat() instead of pathname.
stat() will think the path doesn't exist if there just so happens to be a slash at the end, and since some people, (not everyone), do think to put a slash at the end of their pathname, I'd like to cater to that by detecting whether they used a slash at the end and then remove it.
I'm looking for a portable solution for Windows / Mac / Linux.
Thanks!
I found a solution. I think I should've searched more before asking here.
double directory_exists(char *pathname)
{
std::string str(pathname);
if (!str.empty())
{
while (*str.rbegin() == '\\' || *str.rbegin() == '/')
{
str.erase(str.size()-1);
}
}
struct stat sb;
return (stat((char *)str.c_str(),&sb) == 0 &&
S_ISDIR(sb.st_mode));
}
What's nice about this approach is that it doesn't require C++11, unlike string::back() and string::pop_back().
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 have a regex which I hope means any file with extension listed:
((\\.cpp$)|(\\.cxx$)|(\\.c$)|(\\.hpp$)|(\\.h$))
How to compare it in Qt against selected file?
Your actual RegEx itself doesn't have double backslashes (just when you fit it into a string literal). And you'll need some kind of wildcard if you want to use it to match full filenames. There's a semantic issue of whether you want a file called just ".cpp" to match or not. What about case sensitivity?
I'll assume for the moment that you want at least one other character in the beginning and use .+:
.+((\.cpp$)|(\.cxx$)|(\.c$)|(\.hpp$)|(\.h$))
So this should work:
QRegExp rx (".+((\\.cpp$)|(\\.cxx$)|(\\.c$)|(\\.hpp$)|(\\.h$))");
bool isMatch = rx.exactMatch(filename);
But with the expressive power of a whole C++ compiler at your beck and call, it can be a bit stifling to use regular expressions. You might have an easier time adapting code if you write it more like:
bool isMatch = false;
QStringList fileExtensionList;
fileExtensionList << "CPP" << "CXX" << "C" << "HPP" << "H";
QStringList splitFilenameList = filename.split(".");
if(splitFilenameList.size() > 1) {
QString fileExtension = splitFilenameList[splitFilenameList.size() - 1];
isMatch = fileExtensionList.contains(fileExtension.toUpper()));
}
I need a regular expression utility that will search through a specified directory and return only the first line of each file, or a special 13 digit number on the first line.
Is there a simple and effective way to do this in a regex in c# or vb.net or vb6?
The code I'm trying to search for is this:000999D5, but the 13 digit number I want to return is only on the first line.
Thanks,
Marc
I can't imagine a readily available API request to do this, so you'll have to code this yourself. Nothing too fancy here.
public class ScanDirectory
{
public void WalkDirectory(string directory)
{
WalkDirectory(new DirectoryInfo(directory));
}
private void WalkDirectory(DirectoryInfo directory)
{
// Scan all files in the current path
foreach (FileInfo file in directory.GetFiles())
{
// Do something with each file.
}
DirectoryInfo [] subDirectories = directory.GetDirectories();
// Scan the directories in the current directory and call this method
// again to go one level into the directory tree
foreach (DirectoryInfo subDirectory in subDirectories)
{
WalkDirectory(subDirectory);
}
}
}
(Code is from here: http://www.codeproject.com/KB/cs/ScanDirectory.aspx)
And in every file you'll have to read a first line. You can do this with
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
String firstLine = file.ReadLine();
if (null != firstLine)
{
// do regexp comparison
}
Regex comparison should look like this:
string input = "0123456789132";
// Here we call Regex.Match.
Match match = Regex.Match(input, #"([0-9]{13})",
RegexOptions.IgnoreCase);
// Here we check the Match instance.
if (match.Success)
{
// DO your stuff
}
Probably you'll need to change regexp to match your exact requirements, as they are not very clear at the moment.
I've tried the following short example to find out about a bug in a bigger program I am working on. It looks like QFile doesn't support unix (or the shell's) notation for the home directory:
#include <QFile>
#include <QDebug>
int main()
{
QFile f("~/.vimrc");
if (f.open(QIODevice::ReadOnly))
{
qDebug() << f.readAll();
f.close();
}
else
{
qDebug() << f.error();
}
}
As soon as I replace the "~" with my real home directory path, it works. Is there an easy workaround - some setting to enable? Or do I have to go the "ugly" way and ask QDir for the home directory of the current user and prepend that manually to each path?
Addendum: It's clear that usually the shell performs the tilde expansion so programs would never see that. Still it is so convenient in unix shells that I hoped the Qt implementation for file access would have that expansion included.
You can just create a helper function to do this for you, something like:
QString morphFile(QString s) {
if ((s == "~") || (s.startsWith("~/"))) {
s.replace (0, 1, QDir::homePath());
}
return s;
}
:
QFile vimRc(morphFile("~/.vimrc"));
QFile homeDir(morphFile("~"));
A more complete solution, allowing for home directories of other users as well, may be:
QString morphFile(QString fspec) {
// Leave strings alone unless starting with tilde.
if (! fspec.startsWith("~")) return fspec;
// Special case for current user.
if ((fspec == "~") || (fspec.startsWith("~/"))) {
fspec.replace(0, 1, QDir::homePath());
return fspec;
}
// General case for any user. Get user name and length of it.
QString name (fspec);
name.replace(0, 1, ""); // Remove leading '~'.
int len = name.indexOf('/'); // Get name (up to first '/').
len = (len == -1)
? name.length()
: len - 1;
name = name.left(idx);
// Find that user in the password file, replace with home
// directory if found, then return it. You can also add a
// Windows-specific variant if needed.
struct passwd *pwent = getpwnam(name.toAscii().constData());
if (pwent != NULL)
fspec.replace(0, len+1, pwent->pw_dir);
return fspec;
}
Just one thing to keep in mind, the current solution is not portable to Windows (as per the comments in the code). I suspect this is okay for the immediate question since .vimrc indicates that's not the platform you're running on (it's _vimrc on Windows).
Tailoring the solution to that platform is possible, and indeed shows that the helper-function solution is a good fit since you'll only have to change one piece of code to add that.
It has nothing to do with not supporting UNIX; the expansion of tildes to the user's home directory is a substitution performed by the shell, so yes, you will have to manually replace them.
Please submit a suggestion to the Qt bugtracker.
https://bugreports.qt.io/
Take a look at the C library function glob, which will do tilde expansion (and possibly wildcard expansion and various other functions too).