Click here to Skip to main content
Click here to Skip to main content

Utilities

By , 23 Jan 2012
 

Introduction

I've come across countless situations where routinely used utility functions are simply not available and developers have to write and rewrite them many times over. This article will attempt to provide an array of static utility functions, bundled into a C++ class, that I have collected over the years and used repeatedly in over 50 projects of all shapes and sizes.

These functions are neither a break through in software engineering, nor are they the most optimized, lean and mean implementations. They are simply the most frequently used utility functions from my numerous projects, bundled in the most convenient manner, that has helped me and the developers working with me save many hundreds of hours.

The class and its function calls have evolved in the years to mimic something that has been most practical and convenient to use in all forms of C++ code, and their performance is usually adequate enough for most day-to-day project tasks.

Using the Code

Follow these simple steps to use the code in your Microsoft Visual Studio C++ project:

  1. Add the two files Util.h and Util.cpp into your project.
  2. Add the line #include "Util.h" in the top section of the *.cpp files you intend to use these utility functions in.
  3. Simply call the required static functions, e.g., CString strMyDocuments = CUtil::GetMyDocumentsDirectory().c_str().
  4. Check the "Util.cpp" source file to understand how each function works internally, they are very well commented.

List of Functions and Descriptions

File IO functions best suited for text files

In many projects, the only disk operations that need to be made are read/write operations of small to medium sized text files, usually in the form of log files, or files that store simple user data; on other projects, sizes of arbitrarily small/large files need to be reported or monitored and logged. In any case, these functions provide an easy way to achieve many of the routine file IO tasks that projects require. A few of those functions are listed below, please check the header file for all the available functions.

static bool ReadFile(const _tstring& strFilePath, _tstring& strFileData)
static bool WriteFile(const _tstring& strFilePath, const _tstring& strFileData)

static long GetFileSize(const _tstring& strFilePath)
static __int64 GetFileSize64(const _tstring& strFilePath)

static bool IsFile(const _tstring& strFilePath)

String manipulation function, returns the number of successful sub-strings replaced

Sometimes the only thing that really needs to be done on strings is to find something and replace it with something else, and get to know how many of it there were! This function does exactly that and nothing more! There are also several similar functions for removing white spaces, garbage characters, and trimming.

It replaces all exact matches of strFind found in strSource with strReplace, and returns the number of replacements made.

static long FindReplace(
    _tstring& strSource,
    const _tstring& strFind,
    const _tstring& strReplace)

String tokenizing functions

These are not the fastest or the most sophisticated string tokenizers on the planet; in fact, far from it! But, they are fast enough for most everyday string tokenizing needs, and they are very convenient to use.

static long GetTokenCount(
    const _tstring& strSource,
    const _tstring& strDeliminator)

static _tstring GetToken(
    const _tstring& strSource,
    const _tstring& strDeliminator,
    long lTokenIndex)

Take this example, data from a file needs to be read, the file contains only numbers and new-line characters, you are interested in getting all the numbers, so this is what you can do:

long lTokenIndex = 0;
long lTokenCount = (long) CUtil::GetTokenCount(strUserData, _T("\n"));

for(lTokenIndex = 0; lTokenIndex < lTokenCount; lTokenIndex++)
{
    long lNumber = _tstol(CUtil::GetTokenCount(strUserData, _T("\n"), 
                                               lTokenIndex).c_str());

    // Now you can do what ever you like with the number!
}

Clipboard: simple copy / paste text functions

static void Copy2Clipboard(const _tstring& strData)
static _tstring PasteFromClipboard()

Numeric to string converters

There are countless times that numbers need to be converted to strings in any given project, from putting in file sizes and dates/times into log files, to reporting complex information in the GUI. These functions provide a convenient way to do that by simply using the function on the other side of a string += statement.

The first Long2String function outputs strings with leading 0s; e.g., Long2String(1234, 8); will give you "00001234". This is very useful when you need numbers to always have a set number of digits, like naming a sequence of files with consecutive numbers.

The Double2String function outputs strings with the specified number of digits after the decimal place, unless lPrecision is unspecified or set to 0 or lower, in which case, it doesn't truncate; e.g., Double2String(3.141592653); will return "3.141592653", whereas Double2String(3.141592653, 4); will return "3.1415".

static _tstring Long2String(unsigned long lNumber, unsigned long lPrecision)
static _tstring Long2String(long long lNumber)

static _tstring Double2String(long double dNumber, unsigned long lPrecision = 0)

There are also useful function for finding the number of significant digits, rounding to a certain decimal place, and checking whether a number is a power of 2.

static unsigned long NumberOfDigits(long lNumber)

static double Round(double dNumber2Round, unsigned long lPlaces)
static long Round(double dNumber2Round)

static bool IsPowerOf2(unsigned long iNumber)

String case converters, upper to/from lower

static _tstring ToUpper(const _tstring& str)
static _tstring ToLower(const _tstring& str)

Compare without case sensitivity, returns 0 if both strings are equivalent when ignoring case

static int CompareNoCase(const _tstring& str1, const _tstring& str2)

System time retrieval

It returns a string with the current system date/time in the requested format, which is very useful when logging or displaying date/time to users. A complete list of date/time format modifiers are available here.

static _tstring GetSystemTime(
       const _tstring& strDateFormat = _T("%A, %d/%m/%Y, %H:%M:%S - %Z"))

Convert given number of seconds to hh:mm:ss and vice versa

Most of the time, measurements made or calculations done internally in a project are either in seconds or milliseconds, both of which are useless for logging and displaying to users; on top of that, if the user is required to enter time values, to her, seconds and milliseconds are usually meaningless. These functions provide simple ways to convert them between being meaningful to the user and being meaningful to the computer.

static _tstring GetTime(long lSeconds)
static long GetTime(const _tstring& strTime = _T("00:00:00"))

Get commonly used directory paths

Commonly used user directory paths are not constant! They vary from computer to computer and user to user, that is why these functions are useful in quickly getting the directory you need to use in your code.

Please take a look at this article for details on the usage of these functions.

static _tstring GetWorkingDirectory()
static _tstring GetProgramDirectory()
static _tstring GetProgramFilesDirectory()

static _tstring GetWindowsDirectory()
static _tstring GetSystemDirectory()

static _tstring GetMyDocumentsDirectory()
static _tstring GetMyMusicDirectory()
static _tstring GetMyPicturesDirectory()
static _tstring GetMyVideosDirectory()

static _tstring GetAppDataDirectory()
static _tstring GetLocalAppDataDirectory()

static _tstring GetDesktopDirectory()
static _tstring GetStartupDirectory()

Copy or cut a file into another directory

This function can either copy or cut a file into a directory, creating the entire directory structure of the destination, if necessary.

static bool CopyFile2Directory(
    const _tstring& strSourceFilePath,
    const _tstring& strDestinationDirectory,
    bool bDeleteSource = false)

Directory manipulation functions

Please take a look at this article for more details about the "GetFileList" function.

// Get list of all files in the target directory
static void GetFileList(
	const _tstring& strTargetDirectoryPath,
	const _tstring& strWildCard,
	bool bLookInSubdirectories,
	vector<_tstring>& vecstrFileList)

// Create the entire directory path
static void MakeDirectory(const _tstring& strDirectoryPath);

// Delete the entire directory path, including all files and folders within
static void DeleteDirectory(const _tstring& strTargetDirectoryPath)

// Check whether the given path is a directory
static bool IsDirectory(const _tstring& strDirectoryPath)

// Add "\" to the end of a directory path, if not present
static _tstring AddDirectoryEnding(const _tstring& strDirectoryPath)

// Remove "\" from the end of a directory path, if present
static _tstring RemoveDirectoryEnding(const _tstring& strDirectoryPath)

// Get the name of the directory form a given directory path:
// e.g. C:\Program Files\XYZ, will return XYZ
static _tstring GetDirectoryName(const _tstring& strDirectoryPath)

// Get the directory from a file path
static _tstring GetFileDirectory(const _tstring& strFilePath)

// Get the previous directory from a given directory path
static _tstring GetRootDirectory(const _tstring& strDirectoryPath)

// Get the file name including/excluding the extension from a given file path
static _tstring GetFileName(const _tstring& strFilePath, bool bIncludeExtension = false)

// Get the file extension including/excluding the "." from a given file path
static _tstring GetFileExtension(const _tstring& strFilePath, bool bIncludeDot = false)

// Get the file prefix / suffix
static _tstring GetFileNamePrefix(const _tstring& strFilePath, 
                const _tstring& strDelimiter);
static _tstring GetFileNameSuffix(const _tstring& strFilePath, 
                const _tstring& strDelimiter);

String type converters, ANSI to/from Unicode

These functions use the Win32 API functions WideCharToMultiByte() and MultiByteToWideChar() in a clean and convenient manner. You will also find commented out code within those functions that show other ways to do the conversions, but this commented out code works reliably only on the ASCII character set.

static wstring GetStringW(const string& strA)
static string GetStringA(const wstring& strW)

Registry

Sometimes, all that needs to be done is read/write small pieces of data into the Registry, which doesn't need a heavy and fancy Registry editing tool or class.

static _tstring GetRegistryInfo(
    HKEY hKey,
    const _tstring& strRegistryPath,
    const _tstring& strValueName)

static bool SetRegistryInfo(
    HKEY hkey,
    const _tstring& strRegistryPath,
    const _tstring& strValueName,
    const _tstring& strValue)

Usage example:

_tstring strDirectory = GetRegistryInfo(
    HKEY_LOCAL_MACHINE,
    _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
    _T("ProgramFilesDir"));

bool bSuccess = SetRegistryInfo(
    HKEY_LOCAL_MACHINE,
    _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
    _T("ProgramFilesDir"),
    _T("C:\\Program Files"));

Internet

This function runs the default Internet browser application to open the given URL.

static HINSTANCE OpenURL(LPCTSTR strURL)

Execution

Use this function to open files with their default applications, or run an executable with a set of input parameters.

static bool Execute(
	const _tstring& strFilePath,
	const _tstring& strParameters = _T(""),
	bool bShow = true,
	bool bWait = false)

static bool Execute(
	const _tstring& strCommandLine,
	bool bShow = true,
	bool bWait = false)

Randomness generator

At random times, for random reasons, random things need to be generated!

// Generate random string
static wstring GenerateRandomStringW(long lMaxLength, 
  bool bIncludeAlpha = true, bool bIncludeNumbers = true)
static string GenerateRandomStringA(long lMaxLength, 
  bool bIncludeAlpha = true, bool bIncludeNumbers = true)

// Generate random number between A & B
static float GetRandomNumber(float fA, float fB, float fGrain = 10.0f)
static double GetRandomNumber(double dA, double dB, double dGrain = 10.0)

// Simulate die roll in a bernoulli trial
static bool RollDice(double dProbability)

Hara Kiri

Sometimes the only way out is self destruction... This function simply deletes the program it is called from along with its parent directory.

static void SelfDestruct()

Points of Interest

The code provided here is for unmanaged C++, is Unicode and ANSI compatible, and parts of it may be usable under other operating systems than Windows. If you find the code useful, please leave a comment, it could make my day :-)

History

  • V1.0 - Initial release.
  • V1.1 - Added several new functions and implemented a more user friendly interface as suggested by some developers.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shup
Chief Technology Officer Mind & Machines
Bangladesh Bangladesh
Member
(AKA The Freak), besides being a computer nerd, given his love for extreme sports, is a fire spinner, sky diver, and a XC/DH biker. He juggles his time between computing, research, business, travelling, gourmet cooking, and many other bizarre hobbies.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralgoodJobmembernevstops4 Jan '13 - 20:16 
thanks
GeneralRe: goodJobmemberShup4hrs 12mins ago 
Thanks Smile | :) I'm glad you found it useful. There will be an update soon!
Regards,
 
Shup
Mind & Machines

Generalvery usefull, i like it,memberstonexin30 Jan '12 - 14:04 
thx for u good job.
GeneralRe: very usefull, i like it,memberShup30 Jan '12 - 19:40 
Thanks Smile | :)
Regards,
 
Shup
Mind & Machines

QuestionSelfDestructmembervasvladal23 Jan '12 - 19:53 
The SelfDestruct() doesn't work with win7?
AnswerRe: SelfDestructmemberShup23 Jan '12 - 21:03 
That might be the case, I haven't tested it on Windows 7 yet. Probably to have it working under Windows 7, you'd need administrative privilege for the program. I am not sure, but if you do find a solution to how to make it work under Windows 7, please do let me know. Thanks.
Regards,
 
Shup
Mind & Machines

GeneralRe: SelfDestructmemberAjay Vijayvargiya3 Mar '12 - 1:30 
CUtil::SelfDestruct to do what? I don't understand? I initially thought, it would terminate itself by calling TerminateProcess or doing something similar.
 
But after looking at code, it just deletes the file (the executable file).
It won't work on latest versions of Windows OS (can't comment which one, but after Win2000, it wont). And for that matter, you could have used DeleteFile[^] function instead, followed by loop/sleep and a check if file exists or not. Again, I don't understand why loop (i.e. call batch file again), if file couldn't be deleted. The batch file will run indefinitely. Thanks to ShellExecute which is async and wont block the thread who called this function.
 
BTW, nice set of functions you have. But I recommend you to segregate Windows and non-Windows functions (using #ifdef macros). Further, do use native Windows functions, for windows specific code. You have been mixing ReadFile and fread.
GeneralRe: SelfDestructmemberShup4 Mar '12 - 8:42 
Thanks for the observations. The code's been used mostly for convenience and quick fixes, and as such that's its only purpose Smile | :) For anything more critical, this code is not really recommended.
 
Its also been exclusively used for the Windows environment so the code has never been segregated, but I do agree with you. And I think that's a good idea for the next version when ever I get around to doing it.
 
You are right, the batch will go into an endless loop, that's why the only way to use it is to execute the batch, close all other files that the application might be using, and then exit the program; I should've mentioned that in the article, but it somehow slipped my mind at the time of writing. The idea about the delete thing is to literally self destruct and not leave any traces of the application, this was usually achieved in conjunction with a secure delete application such as sdelete.exe provided by Microsoft.
 
On that point, in the next version I'll also add the secure delete routine!
Cheers,
 
Shup
Mind & Machines

Generalvery useful and handymemberqiuqianren23 Jan '12 - 18:09 
By adding to it day by day, a very handy and useful utility library could be created.
GeneralRe: very useful and handymemberShup23 Jan '12 - 21:01 
Thanks! I'm happy you found it useful.
Regards,
 
Shup
Mind & Machines

GeneralGr8... Good jobmemberLakamraju Raghuram23 Jan '12 - 17:57 
It is a nice collection and can be expanded for more categories like logging utils, tracing utils...
Thanks
GeneralRe: Gr8... Good jobmemberShup23 Jan '12 - 20:56 
Thanks, I am glad you think so and hope you will find it useful.
Regards,
 
Shup
Mind & Machines

GeneralSome commentsmemberMihai Nita30 Jan '09 - 7:33 
Nice collection of tools.
Going quickly thru the code I would like to make some comments.
Please don't take that a critique, more like "peer code review" Smile | :)
 
- ReadFile and WriteFile might have problems reading UTF-16 encoded files (with stuff like strBuffer[lFileSize] = '\0';)
- IsFile using GetFileSize==0: why not stat or access? Zero size means "empty file," not "no file"
- I would change the name from stlstring to something like _tstring. _t is in line with the MS convention of generic text APIs (like _tprintf and Co), while stlstring gives no info that is about string vs wstring (if you don't like _tstring, anything that can convey the info "encoding_neutral_string"
- GetTokenCount: lIndex++; might have problems with MBCS
- case conversion: must make it clear if it is locale sensitive or not. (it is not widely known, but case conversion and comparison are locale sensitive)
- CompareNoCase: there are good reasons to uppercase and then compare, not lowercase (for instance the uppercase of German sharp S ("ß") is "SS", so "weiß" becomes "WEISS". Lowercase("WEISS") = "weiss" != "weiß" (wrong), but uppercase("weiß") = "WEISS" == "WEISS" (correct) )
- GetSystemTime/GetTime are locale insensitive. Document that.
- No Get...Directory should use the registry, never ever. SHGetFolderPath is the right way.
- IsDirectory: FileFinder + CompareNoCase: never do string compare on file/folder names. The case conversion on file systems might be different that the one in the upper layers (NTFS stores a case conversion table on the disk, and there are differences even between XP and Vista, Mac OS X does normalization to NFD). The safe way to know if a file is there is trying to access it (access or CreateFile)
- RemoveDirectoryEnding/AddDirectoryEnding (and all the APIs using them) will have problems with Japanese (there are Japanese characters where the second byte is a '\')
- Wide2Narrow/Narrow2Wide oh, so wrong! Need complete rewrite! ("UNICODE incorporates ASCII" only for the 0-127 range)
- MultiByteToWideChar/WideCharToMultiByte: give some thinking to the flags. Zero is not always the right thing.
- Why the magic "MAX_PATH * 4" in RegKeys stuff? Why 4? Maybe sizeof(TCHAR) instead of 4?
- If OpenURL fails, stop trying, you can't do it better. That code is wrong anyway (.htm has a default set to FirefoxHTML (for instance) and that has a shell\open\command, but .htm does not have a shell\open\command)
- In general, there are a ton of things that might be locale sensitive. Some CRT API will honor a previous setlocale, some will not. So the behavior or most APIs here are unpredictable, really.
- in the header you might consider _T("\\") instead of explicit ifdefs
- you will have problems mixing CRT API with Win32 API. UNICODE affects Win32, _UNICODE affects CRT. So having stlstring depend on UNICODE is wrong, ShellExecute (Win32) using _T("open") (CRT) might have problems. Suggestion: in the header try checking if UNICODE and _UNICODE are both defined or not, and give an error otherwise
GeneralRe: Some commentsmemberShup30 Jan '09 - 8:05 
Hi,
 
Thanks a lot for looking into the code so deeply. This is really the way criticism should be, you set a great example and to say the least its not only helpful, but also admirable.
 
I just hate those kind of critics who leave one line comments/criticism like: "This is so basic", "This is useless" and such, or along that line.
 
As soon as I get some time to put on the code again, I will take into consideration everything that you've said and see what modifications I can make to iron out those creases a bit better.
 
The code posted in this article, has been used mostly for English and on that note, the code has evolved to address quick solutions that works in most cases rather than addressing the extremes, which would've required far more time to develop. And as with all projects, time and funds are always limited, clients simply want the developers to spend more time else where. But yes, I do intent to keep improving these utility functions to perfection, so your help on all the pointers are the best thing that happened to the project so far Smile | :)
 
Regards,
 
Shup
Mind & Machines LTD

GeneralRe: Some commentsmemberShup30 Jan '09 - 8:06 
By the way, pointers, or code snippets that can help are most welcome if you care to share.
 
Shup
Mind & Machines LTD

GeneralRe: Some commentsmemberMihai Nita26 Feb '09 - 9:56 
Sorry for disappearing. I am kind of busy lately, but I promise to get back to you with some pointers and hints.
GeneralJust keep posting 'em...memberloreia20 Jan '09 - 20:25 
...this is getting better and better.
 
Your "ANSI to/from UNICODE" conversion routine is so much more elegant than mine. I was totally unaware of std::transform, and was using WideCharToMultiByte() and MultiByteToWideChar () which is soooo 1970s C-string like logic.
 
I love GetStringW and GetStringA. And it couldn't have come in better moment, I'll be working this weekend on some stuff that requires ANSI to UNICODE conversion Smile | :)
 
Once again, great job.
Thanks a lot,
loreia
GeneralRe: Just keep posting 'em...memberShup21 Jan '09 - 1:58 
Hi,
 
Glad that you found something useful Smile | :)
 
Cheers,
 
Shup
Mind & Machines LTD

JokeRe: Just keep posting 'em... [modified]memberJimD.999927 Jan '09 - 6:05 
See that c++ didn't really come out until the late '80's, and stl until the '90's, you are at least 10 years off Smile | :)
 
Jim
 
modified on Tuesday, January 27, 2009 2:01 PM

GeneralRe: Just keep posting 'em...memberloreia27 Jan '09 - 7:40 
Smile | :)
GeneralRe: Just keep posting 'em...memberShup27 Jan '09 - 7:45 
lol!
 
Shup
Mind & Machines LTD

GeneralRe: Just keep posting 'em...memberAlex Cohn28 Jan '09 - 3:54 
The efficient and strict implementation of GetStringA and GetStringW must use WideCharToMultiByte() and MultiByteToWideChar(), respectedly. Nobody is going to rewrite the full 16-bit encoding tables for all possible "ANSI" code pages.
GeneralRe: Just keep posting 'em...memberzupzup28 Jan '09 - 4:27 
You are right, perhaps using WideCharToMultiByte() and MultiByteToWideChar() wrapped in the convenience of GetStringA and GetStringW would be a great way to get this done to support for a wider range of characters.
 
I think the current implementation GetStringA and GetStringW are more to Shup's theme of the article though, which is to provide simple and quick implementations to get a certain thing done. In this string conversion case, I'm betting he's only focusing on the English or most commonly or frequently used characters in every day use, at least for his projects. If that's the case, a little more detailed description would be helpful.
 
Shup: I also noticed your read/write functions are also purely focused on ASCII text. Its great to use for the convenience, I could use something that was a bit more versatile, like writing text files in UNICODE etc.
 
Cheers
Zzz

GeneralRe: Just keep posting 'em...memberShup28 Jan '09 - 14:49 
Hi,
 
Thanks to everyone here who's been giving me a lot of great suggestions. As soon as I get some time, I will re write the GetString functions using WideCharToMultiByte() and MultiByteToWideChar() as you've suggested and probably also try to change the read/write function codes to better support other text format files. I'll also add some more details on those functions.
 
Regards,
 
Shup
Mind & Machines LTD

GeneralRe: Just keep posting 'em...memberShup29 Jan '09 - 11:58 
I updated the article today with code to use WideCharToMultiByte() and MultiByteToWideChar(). Can you please check whether it was done properly. I tested it and its working as its supposed to in the previous project codes that these functions were used it.
 
Thanks for the pointer and the suggestions. Much appreciated.
 
Shup
Mind & Machines LTD

GeneralRe: code to use WideCharToMultiByte() and MultiByteToWideChar()memberAlex Cohn1 Feb '09 - 1:43 
You should add one to the input string lengths in both functions to account for the null terminator.
 
There is no reason to allocate a SysString in GetStringW(), or even to use a temporary char[] buffer in GetStringA(). Thanks to the std::string(size_t num) constructor, you can simply create a string of desired size and call, in GetStringW():
 
::MultiByteToWideChar(CP_ACP, 0, strA.c_str(), lStringLengthA, &(strW[0]), lStringLengthW);
 
The same trick will work fine for GetStringA().
 
Another thought, I think that CP_THREAD_ACP (unless you compile for WinCE) is most natural.
 
Finally, I would like to address the idea of supercat9 of converting 'déjà' to 'deja' rather than 'd?j?'. This may be done, for sure, but in two steps: first, perform the normal conversion; then test the resulting ANSI string for unexpected '?' characters, and only for these you can follow the wide-char collation table, i.e. if the wide character in input wstring sorts between 'a' and 'b', replace the '?' with 'a'.
GeneralRe: Just keep posting 'em...membersupercat930 Jan '09 - 5:36 
Nobody is going to rewrite the full 16-bit encoding tables for all possible "ANSI" code pages.
 
How about trying to convert a Unicode string to ASCII in 'sensible' fashion, such that 'déjà' becomes 'deja' rather than 'd?j?'. I figured out a way to do it, but it's pretty clunky: if a character sorts between "a" and "b", figure it should translate to either "a" or "A". To determine which, change to uppercase and see if it changes. If so, it was an "a", otherwise an "A".
 
To avoid having to do that sort of testing with every character, I keep a table of the ASCII character associated with each Unicode character (64K byte shared). A little icky, but better than having text laden with question-marks instead of letters.
GeneralRe: Just keep posting 'em...memberShup30 Jan '09 - 5:43 
Hi,
 
I really like your idea!
 
It does actually make more sense to have such a system where 'déjà' becomes 'deja' rather than 'd?j?'
 
I thought at first WideCharToMultiByte() and MultiByteToWideChar() were smart enough to do that!
 
If you are interested in sharing your code, could post your code some where so I can check it out and may be incorporate it into this utility class.
 
Thanks for your input and great idea, that is exactly what this set of functions actually need to do!
 
Regards,
Shup
 
Shup
Mind & Machines LTD

GeneralRe: Just keep posting 'em...membersupercat930 Jan '09 - 8:56 
Here's the essential bit, though it doesn't handle upper/lower case. You could add that using the method I described.
Shared equivMapping(65535) As Char
 
   Shared Function ConvertChar(ByVal Ch As Char) As Char
        If equivMapping(AscW(Ch)) = ChrW(0) Then
            equivMapping(AscW(Ch)) = Ch
            Dim cht As String = Ch & "9"
            If (cht) > "A" AndAlso Ch < "Z99" Then
                If cht > "Z" Then
                    If cht = LCase(cht) Then
                        equivMapping(AscW(Ch)) = "z"c
                    Else
                        equivMapping(AscW(Ch)) = "Z"c
                    End If
                Else
                    For i As Integer = 65 To 89
                        If cht > ChrW(i) AndAlso cht < ChrW(i + 1) Then
                            If String.Equals(cht, LCase(cht)) Then
                                equivMapping(AscW(Ch)) = ChrW(i + 32)
                            Else
                                equivMapping(AscW(Ch)) = ChrW(i)
                            End If
                        End If
                    Next
                End If
                End If
        End If
        Return equivMapping(AscW(Ch))
    End Function
Pretty crummy, but it seems to handle letters sensibly. There are no doubt many punctuation characters which should be handled as something other than question marks, but I don't know any good scheme to handle those.
GeneralRe: Just keep posting 'em...memberShup30 Jan '09 - 9:08 
Hi,
 
Thanks for this bit of code, but to tell you the truth I'm not familiar with the syntax or the function calls you are making.
 
Regards,
 
Shup
Mind & Machines LTD

GeneralSuggestion [modified]memberRedFraggle19 Jan '09 - 23:58 
if i see it correctly, there are no non-static functions, so you may use namespace CUtil instead of class CUtil (shall require no further code changes, just a single replace)
 
(a namespace can be more easily extended inside other headers)
 
----
 
for VC7.1 it seems to be necessary to add
 
#include
 
into Util.cpp
 
modified on Tuesday, January 20, 2009 6:06 AM

GeneralRe: Suggestion [modified]memberShup20 Jan '09 - 1:32 
Hi,
 
Thanks for the suggestion.
 
I think I did consider this at one point, but declined the idea because of some reasons related to the maintenance of all the projects that already use this code.
 
But I will add another version of this into the article using "namespace" in the next update.
 
Regards,
 
Shup
Mind & Machines LTD
modified on Tuesday, January 20, 2009 7:44 AM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 23 Jan 2012
Article Copyright 2009 by Shup
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid