- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
So by putting them into blocks of four he saves time??? Never mind that he has to do four replaces when maybe only one is necessary...
Admin
As a defense, at least he keeps the cases sorted. Also, he avoids scanning the whole string once with Replace by doing many redundant (possibly partial) scans with InStr. He's also protected this code against a change in Hex$ by saying no to the standard library.
Admin
Seeing people doing manual 'encoding' of strings is something I got used to by now, but sorting it in if-statements of 4 completely blows me away. What the...?
Admin
Aaaaah! My eyes!...
Thank god he did not discover Unicode. OrElse this page would have taken much longer to load.
And of course a little gem at the end:
Alex Feinman
Admin
I found a bug: 125 is not equal to 0x7C [:^)]
Admin
my brain hurt now...
Admin
you have far too much time on yoru hands...
Admin
WTF!
Admin
'will this be work then?
Private</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>Function</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>ANSIconvert</FONT><FONT size=2>(</FONT><FONT color=#0000ff size=2>ByVal</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>str</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>As</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>String</FONT><FONT size=2>) </FONT><FONT color=#0000ff size=2>As</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>String
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> Dim</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>strReturn</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>As</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>String</FONT><FONT size=2> = </FONT><FONT color=#008000 size=2>""
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> Dim</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>characters</FONT><FONT size=2>() </FONT><FONT color=#0000ff size=2>As</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>Char</FONT><FONT size=2> = </FONT><FONT color=#008000 size=2>str</FONT><FONT size=2>.</FONT><FONT color=#008000 size=2>ToCharArray
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> Dim</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>character</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>As</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>Char
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> For</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>Each</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>character</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>In</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>characters
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> If</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>Not</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>AscW</FONT><FONT size=2>(</FONT><FONT color=#008000 size=2>character</FONT><FONT size=2>) > 122 </FONT><FONT color=#0000ff size=2>Then
</FONT><FONT size=2></FONT><FONT color=#008000 size=2> strReturn</FONT><FONT size=2> &= </FONT><FONT color=#008000 size=2>character</FONT><FONT size=2>.</FONT><FONT color=#008000 size=2>ToString
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> End</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>If
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2> Next</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>character</FONT>
<FONT color=#0000ff size=2> Return</FONT><FONT size=2> </FONT><FONT color=#008000 size=2>strReturn
</FONT><FONT size=2></FONT><FONT color=#0000ff size=2>End</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>Function
</FONT>Admin
<FONT size=6>WOW! </FONT><FONT size=1>WTF!!! [:P]</FONT>
Admin
Actually he already noticed his blindness and provided a better way (I leave it to the inclined reader to actually implement this):
''' one better manual process is to copy the letter from html and paste into word and save rtf file and find the coresponding string.
Admin
My VB is very rusty. What's OrElse, and how does it differ from Or?
Admin
unlike other languages, where once you hit a true statement in an or it will stop trying to evaluate the rest of the condition and just decend into the if, in vb, it will check every single one regardless.
so in
if false or true or false or false then
bla bla
end if
It will check all of them even after it's hit the true part.
To make vb.net more like a real programming language, they made OrElse, which does work like the C flavor of ||
Ahem. You see, the programmer here was saving time and needless processing by using OrElse so that it won't check the rest of the condition before going into the if statement...
Admin
Mine's rusty too, but "Or" in VB is actually a bitwise operator, not a logical operator. It will usually work as a logical operator anyway if both sides are booleans (because a boolean is internally either 0 or -1, ie. all bits off or all bits on), but if you accidentally put in an integer instead of a boolean or conditional on one side then you're going to get weird behaviour.
I guess "OrElse" is the logical-only version.
Admin
Another big bug:
If InStr(xStr, Chr(240)) > 0 OrElse InStr(xStr, Chr(241)) > 0 Then
'÷247'ø248()
xStr = Replace(xStr, Chr(247), "\'f7")
xStr = Replace(xStr, Chr(248), "\'f8")
End If
<FONT color=#000000>He tests for 240 and 241 (like some lines earlier on) and replaces them with the wrong codes.</FONT>
[:$]
Admin
OrElse and AndAlso are the lazy-evaluation counterparts of the logical Or and And statements.
Something like:
<FONT face="Courier New">If (Not objOne is Nothing) And objOne.SomeProperty = 1 then
...
End If</FONT>
would cause a null-reference in VB.Net, because it WILL evaluate the second part of the if, even if the first part is false. I'm not sure why they chose to keep this very dangerous logic in VB.Net but my guess is it might have something to do with keeping VB6 code easier to convert. (For those who don't follow, there are people who call functions in If statements that have 'side-effects' like changing global variables. These side effects might not occur when using lazy evaluation.)
The correct code would be:
<FONT face="Courier New">If (Not objOne is Nothing) AndAlso objOne.SomeProperty = 1 then
...
End If</FONT>
--
I think that simply replacing all the characters in the string would have been better... My guess is that replace itself does a check for the character being in the string, or at least something similar, before actually starting to do anything with replace.
The downside of using many replaces (even 4 at a time) is that you create a rather large amount of immutable strings which then have to be cleaned up. Mind you, I use replace when it seems handy, so I don't unequivocally denounce replace [:O].
Perhaps it is possible to use a cool regular expression to do this sort of replace, but I'm not going to think about that this early in the morning (7:35am).
Drak
Admin
Or maybe taking a screenshot of Word, paste it into Paint and use a OCR. Don't waste precious CPU cycles doing nothing. Just make it work!
Admin
No this won't work, much too simple. There are gaps. For example characters 147 to 161 are not converted.
Admin
ctrl-C, ctrl-V
ctrl-C, ctrl-V
ctrl-C, ctrl-V
Admin
In a more decent language, all you'd have to do is create a big array holding all the values that you want to convert. Or, even simpler: a table containing all values that might need to be converted. Something like "const Table: array[Char] of string = (...);" in Delphi. Of course, it's a lot of typing to get it working but hey, it does give you the fastest way to convert a character to something else...
Too bad that it's the string concatenation that will also eat up lots of clock cycles...
Admin
That code makes my dog run around in circles and whimper... wait... I don't have a dog...
someone make it stop
Admin
Hey, you can do that in VB.Net...
<FONT face="Courier New">Dim objConvertTable as New Hashtable()</FONT>
<FONT face="Courier New" color=#008000>' add values to convert here, like so: objConvertTable(key) = value
' I know this is not the 'proper' way of doing it, but this way double keys
' aren't checked, so it might be a bit faster in the end. Perhaps it is prudent
' to use the add method until you are sure you haven't got any double keys</FONT>
<FONT face="Courier New">For each strKey as String in objConvertTable.Keys
strText = Replace(strText, strKey, objConvertTable(strKey))
Next
<FONT color=#008000>' at least it looks prettier</FONT> [:)]</FONT>
Drak
Admin
Drak, the difference would be that Delphi would just convert the string array in Delphi to plain initialized data while VB will need to fill it up first through code. So Delphi will perform a lot faster with this code.
It would be nice if you could do exactly the same in VB but I don't think VB allows initialized data structures...
Admin
Okay, I don't do a whole lot of work in .NET and usually need to have the references open in front of me to add two numbers together, but isn't there something native in System.Text.Encoding that would do essentially what's being attempted here (without the bugs, I mean)?
Admin
Depends on exactly what being attempted here. It seems it implements a proprietary escaping scheme for non-printable characters. Without know why they choose this particular escaping method, we're stuck duplicating theirs, which, naturally, is not part of <FONT size=2>System.Text.Encoding. If an alternate escaping scheme were acceptable, then, yes, System.Text.Encoding offers some options.</FONT>
Admin
Katja, VB.Net does allow this [:)].
<FONT color=#0000ff size=2>Dim</FONT><FONT size=2> strManyStrings() </FONT><FONT color=#0000ff size=2>As</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>String</FONT><FONT size=2> = {"a", "b", "c", "d"}
</FONT>I think that's what you were getting at?
Drak
Admin
Yep, drak... That's what I meant. It's not too difficult to create a single array of constants and use the index to get whatever value you need to convert the character too. At least it speeds up the code a bit.
You could argue that you only have to create this table for just a subset of the character type but that means that you have to check if a character is within this subset. That adds a bit more code but it also means less memory required for this table. The speed versus memory discussion...
Now, if this application isn't allowed to use lots of memory then an if/then/else-if.. construction would be the solution. The application would be a bit slower but at least it doesn't need that in-memory table. But considering the size of this table, this is just a silly argument...
One thing I do wonder about... Does VB.NET allow you to specify the type of the array index like Delphi? In Delphi you can write:
const strManyStrings: array[Char] of string = ('\0', '\1', ..., '\255');
And you'd define 256 different string values between the parenthisis. This would allow you to use:
NewValue := strManyStrings['A'];
to convert the character 'A' to the new value.
Does VB.Net allow something similar?
Admin
Most CLR languages allow you to declare "indexers".
In C# it looks like this (VB is similar, I just cbf remembering). I would use hashtables so you can build it in an app, and then serialize it out to disk, and reload where needed. Its not quite as fast as an array, but if the input data is sparse in the space, then its a lot more memory efficient ;)
Admin
Katja,
In my experience you cannot do this with a simple array in VB.Net. You would have to create a HashTable for that (which is indexed by an 'Object' ie. anything). But you cannot initialize that at compile-time as far as I know.
Drak
Admin
<FONT style="BACKGROUND-COLOR: #efefef">Dunno about VB.NET, but in C#, you can either declare an array of a given type, or use an ArrayList or HashTable or other ICollection which is type independant.</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">So for chars, you could say</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">char[] arrChar = {'\0','\1'}</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">or</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">ArrayList arrChar = new ArrayList();</FONT>
Either construct supports indexed access, but the collections objects are nice because you don't need to know the size during declaration, you can call Add and Remove at will. If your objects are sortable, you can call Sort too.
Admin
Well, the fun thing with Delphi is that you can define arrays with any type as index, as long as you're using a simple enumerated type. It's even funnier when you create properties for an object since properties can actually be arrays with any data type as index, including other objects, complete records and whatever else you'd like to use as index. It works because those properties have get/set (read/write) methods assigned to them, which are simply functions that get this index type as parameter...
A hashtable could be used too, but it would be a bit slow in my opinion. First you have to calculate a hash value over the index. This hash value would be the index for another array that contains all data. But unfortunately hash algorithms can result in duplicate values. Hash(Apple) could be equal to Hash(Pear). Thus you'd also need some system in this hash table to respond to those duplicate values, making sure they are still properly stored since you don't want a fruit basket with only Apples. [:D]
So with a hash table you'd still have a few calculations that need to be performed, with maybe one or more comparisons. Hash tables are fine if you need to store a large amount of data with a specific index field in a reasonable small amount of disk space but we're talking here about a list of 256 string values.
But think about it. Delphi accepts any enumerated type as index for an array. Why? Because Delphi will convert those enumerated values into some ordinal value. The array can still be an array with an integer as data type, but Delphi's type checking and internal conversion will make sure you have to use the proper values in your code.
So, in VB you should be able to create an array of 256 strings, right? And you can calculate the ASCII value of a character in VB too, can't you? And this ASCII value is an integer, right? Do I need to spell it out?...[;)]
Admin
C lets one do that, as C considers a char just a tiny integer.
C++ and C# are a bit stricter about type conversions, so you'd need an explicit cast.
<FONT face="Courier New">NewValue = strManyStrings[(int)'A'];</FONT>
Yuck, right...
C# does allow you to define an array as:
<FONT face="Courier New">int[] a = {0, 2, 4, 6, 8};</FONT>
But that's just shorthand for:
<FONT face="Courier New">int[] a = new int[] {0, 2, 4, 6, 8};</FONT>
which is itself just shorthand for:
<FONT face="Courier New">int[] a = new int[5];
a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;</FONT>
However, as Delphi has the same designer and (I believe) the same memory management/garbage collection scheme, it's very likely that Delphi uses the same shorthand.
If your using anything beside integer as an array index, there is almost certainly an hashtable at work behind the scenes.
You have an 1980s Comp Sci class view of hash tables. Modern hashing algorithms are fast & rarely cause collisions. And the basic algorithms and collision resolution is already built into the hashtable class in the .Net framework.
Admin
Delphi.Net uses the same memory management as C# and thus it would construct an array in the similar way as C#. However, the Win32 version of Delphi will recognise these arrays as constants as such and will not generate any code that fills the array. Instead, it adds an initialized data segment to the binary, which is read directly into memory when required. I believe C++ for Win32 will do a similar thing with constants.
About hash tables, it just depends on the type of algorithm that you're using. In general, the hash value is just an integer index for a big array, and each element in this array starts a list of the real elements that you are looking for. That's basically what a hashtable is. It's just an array of lots of smaller tables and you can calculate the proper index for an element by calculating the hash value over the index. People always seem to make it appear as if hash tables are very mysterious things but my dad has showed me how they actually work. It's not too diifcult to write your own version. The only problems are choosing the right hash algorithm and deciding how big the final table has to be. (And think about how to deal with collisions.)
Still, it's no use to change a small array with only 256 elements into a hash table. The hash table would just be bigger and would require more steps to find the right value. The simplest solutions are often the best ones...
Admin
Ok. I'm going to say what everybody else wants to, but won't because they're too intimidated.
Katja...you say you're a "student"...yet you have such a grasp of programming that is way beyond your years. You even make reference to "real-world" coding problems and situations, which baffles me...because no student I have ever known has even come close to grasping a "real-world" programming issue.
Having said that, you sound like a brilliant person masquerading as a college student.
Unless it's because you're from the Netherlands and people there are smarter than us dumb Americans.
Admin
Thank you. [:P]
It's just the way I've been raised. My dad often works at home so when I was small, I would always be looking at what he was doing. It got me quite interested. Besides, we had about 6 or 7 different computers at home so I had enough material to teach myself a few things. I've done an IQ test and I have an IQ of around 140, which seems to be quite high. I learn fast. I even helped my dad sometimes with his work when I was a bit older, and when he realized I had a real knack for this. And he wasn't creating any simple GUI software either. I think I learned more at home than at school...[:S]
Admin
<FONT style="BACKGROUND-COLOR: #efefef">@Katja: When you graduate are you going to have your pick of the best programming jobs in the Netherlands?</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">Or will you work with your dad as a contractor?</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">Either way...you're going to be making some booku cash.</FONT>
Admin
Yep, once I've finished studying, the contractor who contracted my dad will likely contract me too. I could in fact start immediately for them if I like, but I prefer to have a diploma first.
Admin
I kinda envy you Katja. You are going to be making so much money.
<FONT style="BACKGROUND-COLOR: #efefef">You go girlfriend.</FONT>
Admin
Thanks, I do hope so because right now, I don't have that much... [;)]
Admin
Hmm, I never actually though anything strange about Katja's knowledge...
Must be because I've been at computing since I was about 7, and learned most of my skills from watching my older brother (he's 16 months older). We used to make games together on a Vic 20 (I did the graphics, he wrote the programs) in those days.
I agree with Katja: what you learn at school is nothing compared to what you can learn by yourself at home if you are truly interested.
Hashtables are not really mysterious, but in VB.Net you have a pre-made Hashtable object, so people don't have to think about how they work ;)
Using the character value as an index is a good idea in this case, I agree. Hadn't thought of that yet. I think if I was actually solving the problem it would have hit me at some moment. I only have an IQ of 124 (or used to, when I was 12 years old), so I'm going to be a bit slower than Katja [:P]
Drak
Admin
I once did an exam where you had to find the next number in the sequence. Except there were two possible answers, given the numbers listed, depending on whether the pattern was based on addition or multiplication. The question was multiple choice though and both possible answers were listed. I decided the addition based one was simpler and thus more likely.