我正在制作一个简单的 Cocoa 程序,可以将文本编码为二进制并将其解码回文本。我试图制作这个脚本,但我什至还没有接近完成它。谁能帮我?这必须包括两个文本框和两个按钮或任何最好的,谢谢!
1 回答
这有两个部分。
第一种是将字符串的字符编码为字节。您可以通过向字符串发送dataUsingEncoding:
消息来做到这一点。您选择的编码将决定它为每个字符提供哪些字节。从 开始NSUTF8StringEncoding
,然后尝试其他编码,例如NSUnicodeStringEncoding
,一旦你开始工作。
第二部分是将每个字节的每一位转换为'0'
字符或'1'
字符,例如,以 UTF-8 编码为单个字节的字母 A 将表示为01000001
.
因此,将字符转换为字节,并将字节转换为表示位的字符。这两个是完全独立的任务;第二部分应该适用于任何字节流,包括任何有效的编码字符流、任何无效的编码字符流,以及实际上任何不是文本的东西。
第一部分很简单:
- (NSString *) stringOfBitsFromEncoding:(NSStringEncoding)encoding
ofString:(NSString *)inputString
{
//Encode the characters to bytes using the UTF-8 encoding. The bytes are contained in an NSData object, which we receive.
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
//I did say these were two separate jobs.
return [self stringOfBitsFromData:data];
}
对于第二部分,您需要遍历bytes
数据。交流for
回路将在那里完成工作,看起来像这样:
//This is the method we're using above. I'll leave out the method signature and let you fill that in.
- …
{
//Find out how many bytes the data object contains.
NSUInteger length = [data length];
//Get the pointer to those bytes. “const” here means that we promise not to change the values of any of the bytes. (The compiler may give a warning if we don't include this, since we're not allowed to change these bytes anyway.)
const char *bytes = [data bytes];
//We'll store the output here. There are 8 bits per byte, and we'll be putting in one character per bit, so we'll tell NSMutableString that it should make room for (the number of bytes times 8) characters.
NSMutableString *outputString = [NSMutableString stringWithCapacity:length * 8];
//The loop. We start by initializing i to 0, then increment it (add 1 to it) after each pass. We keep looping as long as i < length; when i >= length, the loop ends.
for (NSUInteger i = 0; i < length; ++i) {
char thisByte = bytes[i];
for (NSUInteger bitNum = 0; bitNum < 8; ++bitNum) {
//Call a function, which I'll show the definition of in a moment, that will get the value of a bit at a given index within a given character.
bool bit = getBitAtIndex(thisByte, bitNum);
//If this bit is a 1, append a '1' character; if it is a 0, append a '0' character.
[outputString appendFormat: @"%c", bit ? '1' : '0'];
}
}
return outputString;
}
位 101(或 1100101)
位实际上只是以 2 为基数的数字。西方世界的人类通常以 10 为基数写出数字,但数字是一个数字,无论它是用什么基数写的,每个字符,每个字节,甚至每个位,都是只是一个数字。
数字(包括位)从最低的位置开始计数,根据基数被提高到的指数来计算该位置的大小。我们想要位,所以基数是 2,所以我们的位置值是:
- 2^0 = 1:个位(最低位)
- 2^1 = 2:二进制位(下一个高位)
- 2^2 = 4:四人组
- 2^3 = 8:八分之二
依此类推,最多 2^7。(请注意,最高指数正好比我们所追求的位数小一;在这种情况下,7 对 8。)
如果这一切让你想起小时候读过的“个位”、“十位”、“百位”等,那应该是:原理完全相同。
因此,一个字节(如 65)(在 UTF-8 中)完全表示字符“A”,是以下各项的总和:
2^7 × 0 = 0
+ 2^6 × 0 = 64
+ 2^5 × 1 = 0
+ 2^4 × 0 = 0
+ 2^3 × 0 = 0
+ 2^2 × 0 = 0
+ 2^1 × 0 = 0
+ 2^0 × 1 = 1
= 0 + 64 +0+0+0+0+0 + 1
= 64 + 1
= 65
当您小时候学习以 10 为底的数字时,您可能注意到十是“10”,一百是“100”,等等。在底数 2 中也是如此:因为 10^x 是“1”,然后是 x以 10 为底的“0”,2^x “1”后跟以 2 为底的“x”0。因此,例如,以 2 为底的 64 是“1000000”(计算零并与表格进行比较以上)。
我们将使用这些精确的二的幂数来测试每个输入字节中的每个位。
寻找比特
C 有一对“移位”运算符,它们将在数字的低端插入零或删除数字。前者叫做“左移”,写成<<
,你可以猜反了。
我们要左移。我们想将 1 左移我们所追求的位数。这完全等同于将 2(我们的基数)提高到该数字的幂;例如,1 << 6
= 2^6 = “1000000”。
测试位
C 也有一个用于位测试的运算符;它是&
按位与运算符。(不要将此与&&
逻辑AND运算符混淆。&&
用于在做出决策时使用整个真/假值;&
是处理值中的位的工具之一。)
严格来说,&
不测试单个位;它遍历两个输入值的位,并返回一个新值,其位是每个输入对的按位与。所以,例如,
01100101
& 00101011
----------
00100001
当且仅当两个相应的输入位也是 1 时,输出中的每个位都是 1。
把这两件事放在一起
我们将使用左移运算符给我们一个数字,其中设置了一位,即第 n 位,即2^n,然后使用按位与运算符来测试在我们的输入字节。
//This is a C function that takes a char and an int, promising not to change either one, and returns a bool.
bool getBitAtIndex(const char byte, const int bitNum)
//It could also be a method, which would look like this:
//- (bool) bitAtIndex:(const int)bitNum inByte:(const char)byte
//but you would have to change the code above. (Feel free to try it both ways.)
{
//Find 2^bitNum, which will be a number with exactly 1 bit set. For example, when bitNum is 6, this number is “1000000”—a single 1 followed by six 0s—in binary.
const int powerOfTwo = 1 << bitNum;
//Test whether the same bit is also set in the input byte.
bool bitIsSet = byte & powerOfTwo;
return bitIsSet;
}
我应该承认一点魔法
按位 AND 运算符不会计算为单个位 - 它不会仅计算为 1 或 0。请记住上面的示例,其中&
运算符返回 33。
bool
类型有点神奇:任何时候将任何值转换为,bool
它都会自动变为 1 或 0。任何不是 0 的都变为 1;任何东西都0
变成了0
。
Objective-CBOOL
类型不这样做,这就是我bool
在上面的代码中使用的原因。你可以随意使用任何你喜欢的东西,除了你通常应该BOOL
在处理任何需要 a 的东西时使用BOOL
,特别是在覆盖子类中的方法或实现协议时。您可以自由地来回转换,但不是无损的(因为bool
如上所述会更改非零值)。
哦,是的,你也谈到了文本框
当用户单击您的按钮时,获取stringValue
您的输入字段,stringOfBitsFromEncoding:ofString:
使用合理的编码(例如 UTF-8)和该字符串进行调用,并将结果字符串设置为stringValue
您的输出字段的新字符串。
额外积分:添加一个弹出按钮,用户可以使用该按钮选择编码。
额外的额外功劳:使用所有可用编码填充弹出按钮,无需硬编码或硬敲击列表。