Как заглавные и строчные буквы различаются только на один бит? - PullRequest
13 голосов
/ 26 августа 2010

Я нашел один пример в книге «Сети передачи данных и коммуникации», написанной Бехрузой Форузаном, о прописных и строчных буквах, которые отличаются только на один бит в 7-битном коде.

Например, символ A равен 1000001 (0x41), а символ a - 1100001 (0x61). Разница в бите 6, который равен 0 в верхнем регистре и 1 в нижнем. Если мы знаем код для одного случая, мы можем легко найти код для другого, добавив или вычтя 32 в десятичном виде, или мы можем просто перевернуть шестой бит.

Что все это значит?

Я очень запутался во всех этих вещах. Может ли кто-нибудь привести примеры того, как эти вещи действительно работают?

Ответы [ 7 ]

35 голосов
/ 26 августа 2010

Давайте использовать случай, который вы найдете более знакомым: база 10.

  1. Предположим, у нас есть базовый 10 компьютер, где каждый 10-битный хранит значение от 0 до 9, а 10-байтовый имеет длину 5 10 бит, так что каждый байт может хранить 100 000 значений (от 0 до 99 999).

  2. Вы хотите назначить буквы определенным позициям в 10 байт, чтобы этот компьютер мог обмениваться текстовыми данными с другими компьютерами. Один из способов сделать это было бы так:

    00101 A    00201 a
    00102 B    00202 b
    00103 C    00203 c
    00104 D    00204 d
    00105 E    00205 e
    00106 F    00206 f
    00107 G    00207 g
    00108 H    00208 h
    00109 I    00209 i
    00110 J    00210 j
    00111 K    00211 k
    00112 L    00212 l
    00113 M    00213 m
    00114 N    00214 n
    00115 O    00215 o
    00116 P    00216 p
    00117 Q    00217 q
    00118 R    00218 r
    00119 S    00219 s
    00120 T    00220 t
    00121 U    00221 u
    00122 V    00222 v
    00123 W    00223 w
    00124 X    00224 x
    00125 Y    00225 y
    00126 Z    00226 z
    
  3. Видите ли вы, что каждая строчная буква отличается от заглавной буквы только одной 10-битной цифрой в 3-м столбце справа? Он не должен был проектироваться таким образом. Это было просто удобно, потому что в любое время, когда мы хотим изменить регистр букв, мы можем просто изменить одну из цифр (10 бит), не заботясь о том, что представляет собой остальная часть числа, или не беспокоиться о двадцати шести различных преобразованиях, когда мы можем сделать один . Мы не могли бы выбрать вторую цифру, потому что вместо 100, они были бы только 10 и перекрывались.

  4. Теперь в базе 2 он точно такой же, но вместо каждого бита, представляющего 0-9, он может представлять только 0-1. Использование восьми 2-битных дает нам только 256 возможных комбинаций, 0-255. Коды ASCII для букв верхнего и нижнего регистра в двоичном виде выглядят так:

    01000001 A        01100001 a
    01000010 B        01100010 b
    01000011 C        01100011 c
    01000100 D        01100100 d
    01000101 E        01100101 e
    01000110 F        01100110 f
    01000111 G        01100111 g
    01001000 H        01101000 h
    01001001 I        01101001 i
    01001010 J        01101010 j
    01001011 K        01101011 k
    01001100 L        01101100 l
    01001101 M        01101101 m
    01001110 N        01101110 n
    01001111 O        01101111 o
    01010000 P        01110000 p
    01010001 Q        01110001 q
    01010010 R        01110010 r
    01010011 S        01110011 s
    01010100 T        01110100 t
    01010101 U        01110101 u
    01010110 V        01110110 v
    01010111 W        01110111 w
    01011000 X        01111000 x
    01011001 Y        01111001 y
    01011010 Z        01111010 z
    

    Так же, как и раньше, они отличаются только одной 2-битной цифрой, здесь, в 6-м столбце справа. Мы не могли бы использовать цифру чуть правее (меньше), потому что тогда списки перекрывались бы (2 ^ 5 = 32, и соответственно мы использовали все биты с 0 по 5, но 2 ^ 4 = 16, что не могло охватывать 26 букв алфавита).

  5. Просто для небольшого пояснения, вот пример того, что означают эти двоичные значения. Давайте возьмем один для G. Чтобы понять, что означает 01000111 в двоичном виде:

     Pos:   7  6  5  4  3  2  1  0
     Bit:   0  1  0  0  0  1  1  1
     Val: 128 64 32 16  8  4  2  1
    Mult:   0 64  0  0  0  4  2  1
     Add: 64 + 4 + 2 + 1 = 71, which is the ASCII code for G.
    

    То же самое для буквы G в специальной системе Base 10, которую я построил выше:

      Pos:     4    3    2    1    0
    10Bit:     0    0    1    0    7
      Val: 10000 1000  100   10    1
     Mult:     0    0  100    0    7
      Add: 100 + 7 = 107, which is my special 10ASCII code for G.
    

    Посмотрите на строку "Val" для двоичного файла. Вы видите, что, начиная справа, каждое значение вдвое больше предыдущего? Удваивая каждый раз, мы получаем 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 и так далее. Вот как позиция двоичной цифры определяет ее значение, точно так же, как позиция десятичной цифры определяет ее значение с степенями 10: 1, 10, 100, 1000, 10000, 100000 и т. Д.

    Я понимаю, что это кажется глупым, потому что все, что я сделал, это преобразовал 107 в 107 ... но 107 это не просто число, это сокращенная форма для:

    1 hundreds + 0 tens + 7 ones.
    

    Другой способ, которым мы могли бы представить, это

    0 x 10^4 + 0 x 10^3 + 1 x 10^2 + 0 x 10^1 + 7 x 10^0.
    

    Аналогично, 01000111 - это не просто двоичное число, это сокращенная форма для

    0 x 2^7 + 1 x 2^6 + 0 x 2^5 + 0 x 2^4 + 0 x 2^3 + 1 x 2^2 + 1 x 2^1 + 1 x 2^0
    

    То, что я вам уже показал:

    0 + 64 + 0 + 0 + 0 + 4 + 2 + 1
    = 64 + 4 + 2 + 1
    = 71
    

Кроме того, вы, возможно, задавались вопросом, что означают 0x41 и 0x61. Часть 0x указывает на то, что следующие цифры следует понимать как шестнадцатеричные, то есть основание 16. В нашей системе счисления всего 10 цифр, поэтому нам нужно как-то еще 6 цифр. Таким образом, шестнадцатеричное число использует цифры 0-9 и рассматривает буквы AF как оставшиеся цифры, где A - от 10 до F как 15. Шестнадцатеричное очень удобно для компьютеров, поскольку 16 - это степень 2, а 8-битный байт, таким образом, для кодирования требуется ровно две шестнадцатеричные цифры (и каждая шестнадцатеричная цифра кодирует ровно четыре двоичных цифры). Взяв 0x41, расширив 4 до его двоичного представления 0100 и расширив 1 до его двоичного представления 0001, вы получите 01000001, который, как вы видите, представляет собой код для A, как показано. Чтобы преобразовать его в десятичную, это 4 x 16 + 1 x 1 = 65. Мы умножаем 4 на 16, потому что каждая последующая шестнадцатеричная цифра влево в 16 раз превосходит предыдущую цифру, следуя той же схеме, что я показал вам выше для оснований 2 и 10. .

Надеюсь, этого будет достаточно, чтобы вы поняли немного больше о двоичных кодах и кодах ASCII.

Примечание 1: Причина в 8 битах в байте вместо 2, как вы могли бы подумать, заключается в том, что еще в первые дни вычислений было решено, что 8 является гораздо более полезным числом битов2-битный «байт» будет кодировать только 4 значения.Для передачи только прописных и строчных букв алфавита потребуется 3 байта!В двоичном коде нет ничего, что заставляло бы выбирать 8 бит на байт, за исключением того, что 8 также является степенью 2, что упрощает большую часть математики, связанной с работой с двоичной информацией, и лучше выравнивает края.Если бы они выбрали 6 бит на байт, я уверен, что все получилось бы неловко, и не использовал бы весь диапазон доступных значений.

Примечание 2: Моя система из пяти бит в 10 байт основана на непрактичности использования десяти 10 бит на байт, что дает действительно огромное число, которое потратило бы много места для хранения.Я выбрал пять, потому что десять делится на него поровну, что, несомненно, будет полезно.(Первоначально, мой ответ использовал десять 10 бит на 10 байт, но он был слишком чертовски большим!)

3 голосов
/ 26 августа 2010

Эта связь между заглавными и строчными буквами была преднамеренной. Когда был сформулирован код ASCII, компьютерное оборудование было примитивным, и для сохранения каждого байта требовалось программное обеспечение. Для переключения одного бита требуется совсем немного оборудования или кода.

2 голосов
/ 26 августа 2010

Чтобы сложить или вычесть 32, вы должны сначала узнать, больше или меньше символ «А».

Когда эта книга была написана, большинство языков программирования не использовало Strings или .equalsIgnoreCase. Это было до i18n, и когда у компании был сервер, вы должны были к нему подключиться (например, xterm) и получить меню командной строки. То, что он описывает, обычно использовалось для создания приятного меню без учета регистра для ваших пользователей, используя числовое расположение таблицы ascii.

Это может быть очень быстро, потому что есть побитовые инструкции ассемблера для выполнения математических операций в любом направлении, независимо от того, являются ли символы уже прописными или строчными.

с = с | 32 // в верхний регистр

c = c & (1 + 2 + 4 + 8 + 16 + 0 + 64 + 128) // в нижнем регистре

Скажем, у вас был Java-подобный язык без объектов или стандартных библиотек. Ваш сетевой автор предлагает вам написать следующий код:

    public static void main()
    {
        println("What would you like to do?");
        println("Inventory (inv)");
        println("Reports (rep)");

        char[] ca = readUserInput();        
        for (int i = 0; i < ca.length; i++)
            ca[i] = ca[i] | 32;  // convert to uppercase, by ensuring bit 32 is set

        if (compareInput(ca, "INV") == true)
            doInventory();
    }

Вы пытались выполнить поиск в Google, а иногда вводили имя человека с большой буквы?

1 голос
/ 31 октября 2012

Я думаю, что большинство из этих ответов излишне сложны и иногда снисходительны.

Отображение десятичных знаков в ascii произвольно и не имеет никакого отношения к пониманию того, как работает база 2 или база 10.Это чисто для удобства.Если кто-то ошибочно закодировал символ нижнего регистра, но имел в виду верхний регистр, более удобно просто перевернуть один бит вместо того, чтобы перекодировать целый байт.Менее склонны к человеческим ошибкам, чтобы просто перевернуть один бит.Если на выходе получается «a», но мы хотели «A», по крайней мере, мы знаем, что мы правильно поняли большую часть бита, и нам просто нужно перевернуть 2 ^ 5, чтобы сложить или вычесть 32. Это так просто.Зачем выбирать именно бит 5 (это не 6, как некоторые говорили, вы начинаете с 0 ..), ясно, что именно этот имеет смысл удовлетворять двум диапазонам из 26 символов только с одним переключением бита.Если бы вы сделали это на менее значимом бите, вам пришлось бы переворачивать более одного.

1 голос
/ 26 августа 2010

http://asciitable.com/

0x61 is hexadecimal for 97 = a
0x41 is hexadecimal for 65 = A

Таким образом, вычитание / добавление десятичного числа 32 - это действительно способ преобразования в верхний / нижний регистр.

Z is 90 = 0b1111010    = 0x5A
z is 122 = 0b1011010   = 0x7A

Что составляет разницу 0b01000000 в двоичном или0x20 или 32 в десятичном виде.

Таким образом, переключение 6-го бита изменяет регистр.

1 голос
/ 26 августа 2010

посмотрите, 6-й бит = 32, поэтому, если вы перевернете его, вы вычтете или добавите 32

Bit value
1   1
2   2
3   4
4   8
5   16
6   32 (32 = hex 20)

Теперь, если вы посмотрите здесь http://asciitable.com/,, вы увидите таблицу ascii для всех символов и заметите, что A = 65 и a = 97

0 голосов
/ 24 сентября 2018
template<char TLBound, char TUBound>
struct CharRange
{
    enum 
    {
        LBound = TLBound,
        UBound = TUBound
    };

    static bool InRange(char ch)
    {
        return (ch >= LBound)  && (ch <= UBound);
    };
};

typedef CharRange<'a', 'z'> lcaseLetters;
typedef CharRange<'A', 'Z'> ucaseLetters;

char toUpper(char ch)
{
    if(lcaseLetters::InRange(ch))
    {
        return (ch ^ (0x1 << 5));
    }

    return ch;
}

char toLower(char ch)
{
    if(ucaseLetters::InRange(ch))
    {
        return (ch ^ (0x1 << 5));
    }

    return ch;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...