Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 227
Текст из файла (страница 227)
Написание лучших и более общих функций ввола даты оставлено в качестве упражнений [9 Г.6[9-10]). Вот простая тестовая программа: Г4. Стандартные фасеты чвб11е (сбп» дд 8 8 ~Ы М Ва1е()) сои!«сЫ «епд1; са!сб (Ва!е: Вад с(а1е е) ( сои! «Некорректная дава: ' «елобу «епй1; Обратите внимание, что с(о уе1 с(а1е() воспримет н бессмысленные даты, такие как Гбигздоу Ос!обег 7, ! 998 // 7 октября 1998 года, четверг и ! 999/Реб/8 ! Проверка сочетаемости года, месяца, числа и (необязательного) дня недели осуществляется в конструкторе.Ва1е. Именно класс Ва1е должен знать, что является корректной датой, Ва/е 1л не обязан разделять это знание, Можно написать уе/оа1() или Ыо 5е1 с/а1е() таким образом, чтобы они строили догадку о смьюлс числовых значений.
Например очевидно, что 12 лизи 1922 означает не 1922 число 12 года. То есть мы могли бы «догадаться», что числовое зна- чение, которое нс может быть числом введенного месяца, является годом. Такие «до- гадки» могут оказаться полезнымн в конкретном ограниченном контексте. Однако онп не являются «волшебной палочкой» для более общих случаев: !2лзай 15 может указывать на любой год из следующих; 12, 15, 1912, 1915, 2012 или 2015.
Иног- да лучшим подходом является расширение нотации подсказками, которые однознач- но определяют год и число. Например, «1-е» и «15-е» очевидно являются числами. ,Аналогично, «751 до н.эж) и «1453 н.эг» явно означают годы. Г.4.5. Классификация символов При чтении символов часто возникает задача их классификации с целью придания смысла прочитанному. Например, чтобы прочесть число, процедура ввода должна знать, какие символы являются цифрами. Это похоже на пример из 9 6.1.2, который демонстрирует использование стандартных функций классификации символов при синтаксическом разборе ввода, Естественно, классификация символов зависит от используемого алфавита.
Для решения задач классификации символов в локализации имеется фасет с1уре. Символ классифицируется в соответствии с перечислением по имени шаек: с1аззз!д: с!уре базе( риб11с спит таз!г ( зрасе = 1, рмш= 1«1, сп1г! = 1«2, иррег = 1«8, !оюег = 1«4, // действительные значения зависят от реализаяии // разделитеяи (влокализаиии "С': ' ', ",и', ''ч!', . ) // сил!волы управления печатью // управляющие ею«волы // сил!волы в верлнел! регистре // сил!волы в нижнеи регистре Приложение Г Локализация 1002 а!рЬа = 1«5, д!д(( = 1«б, риис( = 1«1, х((!у(1 = 1«В, а!лат=а(рЬа ) ((!у(1, угарЬ=и!пит) риис( // буквы сифавита // десятичные цифры // силшолы пунктуации // шестнадцалгеричные цифры Оилфавитно-цифровые сил(волы 1а6(е['а') == !ошег) а!рЬи ) хд(у(( (а61е['1'] == Ы! уа (а61е[' ) == красе При такой реализации (а61е[с] $ т отлично от нуля, если с является т, и Π— в противном случае.
Фасет с(уре определяется следующим образом: (етр!а(е <с1аяя СЬ> с(акк кЫсс(уре риЬ!(с !оса!власе(, риЬ!(с с(уре Ьаке 1 риЬйс: (уредей СЬ сЬаг 1уре; ехр!(с!1 с(уре)я(ее 1 г = 0), 6оо(!к)такЬ т, СЬс) сопя(, //'с" является т"? // лол~ести(пь классификацию каждого СЬ из /6:е) в ш сопя1 СЬ*(я)соля( СЬ* 6, сопя( СЬ' е, таяЬ* о) соля(; соля1 СЬ*ясап (я)такЬт, сопк1 СЬ*6, сопя1СЬ*е) сопк1, //найти т сопя1 СЬ* ксан побтакЬ т, сопк1 СЬ* Ь, солк1СЬ* е) сопя1, // найти нет СЬ (оиррег)СЬ с) сопк1; сопя( СЬ" (оиррег)СЬ' Ь, соля! СЬ' е) сопя1; СЬ (о!оъег)СЬ с) сопк1; соля( СЬ* 1о!ошег) СЬ* 6, сопя( СЬ* е) сопя1; // преобразовать /6:е) СЬ кои(еп)сЬаг с) сопя(; сопк1 сЬаг' ш!((еп)сопя( сЬаг" Ь, сопя( сЬаг' е, СЬ" 62) соля1; саог пагго(о]СЬ с, сЬаг ((еЯ сон к1 сопя( СЬ* паггош)сопя( СЬ* Ь, сопя1 СЬ' е, сЬа г с(еЯ сЬа(» Ь2) сопя(; таас (оса!ег(д(((„ //идентификатор фосета Ц Г2, 5 ГЗ, 5 ГЗ. ! ) Тип таяЬ не зависит от конкретного типа символов.
Поэтому перечисление помегцепо в [не являющийся шаблоном) базовый класс. Очевидно, что п(аяЬ отражает традиционную для С и С »+ классификацию Я 20А.)). Однако для различных наборов символов различные значения символов попадут в разные классы. 11апример, для набора символов АБСП целое значение 125 означает символ ')', являющийся знаком пунктуации [рипа(). А в датском национальном наборе символов 125 означает гласпу(о ей», которая в датской локализации должна классифицироваться как а1рЬа. Классификация называется «маской» [шая)г), потому что традиционной эффективной реализациен классификации символов для небольших наборов символов является таблица, в которой для каждого элемента хранится битовое представление классификации. Например: 1ООЗ Г.4.
Стандартные фасвты рго1ес1е<1: -с!уре(); // вирглуольные с!о функции" (ель у Г.4. !) ); Вызов ся(т, с) осуществляет проверку принадлежности символа с к классификации и. Например: !п1 соил! ярасея(сопягя1г!пуй з, сопя!!оса!ей !ос) ( сопя1 с1уре<сИаг й с1 = ияе Хасе1<сгуре<сИаг»(!ос)' т11= О; гог(я1гтдзсопя! 11ега1ог р — — я 6еу!п(~г р! = кепд(); +«р) (г (с!ля(с1уре Ьаяезярасе,'р)) ++Ь 44 разделитель в соответствии с сг ге!ига Ь Обратите внимание, что (я() можно также воспользоваться для проверки принадлеж- ности символа к одной из нескольких классификаций: с1!я(ссуре Ьаяелярасе)с1уре Ьаяезрипсг, с); Олвллетслли с вс1разделителеи О или знскол~ препинания у Вызов !я(т, Ь, о) определяет классификацию каждого символа из (Ь, е) и помещает ее в соответствующую позицию массива и.
Вызов ясап !я(т, Ь, е) возвращает указатель на первый символ в (Ь, е), являющийся т. Если пи один символ не относится к классификации т, возвращается е. Как всегда в случае стандартных фасетов, открытые функции-члены реализованы путем вызова своих виртуальных «с(о функцийь . Простая реализация может выглядеть так: 1етр!а1е <с!аяя СИ> сопя1 СИ* я1ф с1уре<СИ "с!о ясап !я(таяЬ т, сопи СИ'6, сопя! СИ* е) сопя1 ( гоИ!!е (Ьые йй ~!я(т,*Ь)) .и-6; ге!игл Ь, Вызов ясап по1(т, Ь, е) возвращает указатель на первый символ из (Ь, е), который не является т. Если все символы принадлежат классификации и, возвращается е.
Вызов 1оиррег(с) возвращает с в верхнем регистре, если зто возможно в используемом наборе символов, и сам с — в противном случае. Вызов 1оиррег(Ь, е) преобразует каждый символ диапазона (Ь, е) в верхний регистр и возвращает е. Простая реализация может выглядеть следующим образом: 1етр!и1е <с!аяя СИ> сопя! СИ*ягд.сгуре СИ з1о иррег(СИ*И, сопя! СИ*е) лог (; Ьые; ++Ь) 'Ь =1оиррег(*Ь); ге1игп е; Функция 1о4ощег() аналогична 1оиррег() за исключением того, что она преобразует в нижний регистр. 1004 Приложение Г Локализация Вызов ш?йеп(с) преобразует символ с в соответствующее значение СЬ.
Если набор символов СЬ предоставляет несколько символов, соответствующих с, стандарт определяет, что должно использоваться «простейшее разумное преобразование . Например, госои? «ияе ?ас«Г<стуре<шсЬаг Г»(сисоиб уег?ос()) вййеп('е') выведет разумный эквивалент символа е в локализации потока тосои?. С помощью шЫеп() можно осуществлять и преобразования между не связанными друг с другом представлениями символов, такими как АЯСП и ЕВС?3?С.
Для примера предположим, что сугцествует локализация ебсй?с: сЬагЕВС«йС е = иве ~асс?<с?уре<сЬаг»(ебсй?с) ипйеп('е'~; Вызов шЫеп(Ь, е, и) берет каждый символ из диапазона ?Ь, е) и помещает «расширенную» версию в соответствующую позицию массива и. Вызов паггого(сЬ, йе?) выдает значение сйаг, соответствующее символу сЬ типа СЬ. И снова используется «простейшее разумное преобразование>. Если не существует сЬаг, соответствующего СЬ, возвращается йе?.
Вызов паггого(Ь, е, йеу", о) берет каждый символ из диапазона (Ь, е) и помешает «суженную» версию в соответствуюшую позицию массива и. Общая идея состоит в том, что пагголо() преобразует из большего набора символов в меньший, а ш?йеп() выполняет обратную операцию. Для символа с из меньшего набора символов мы ожидаем, что: с == паггош(пяйеп(с), 0) /( не гарантируется Так и есть при условии, что символ шй?еп(с), имеет только одно представление в «меньшем наборе символов».
А зто не гарантируется. Если символы сЬаг не являются подмножеством большего набора символов (СЬ), следует ожидать нестыковок и потенциальных проблем в коде, работающем с символами в общем виде. Точно так же и для символа сЬ из большего набора символов мы могли бы ожидать: ияйеп(паггосо(сЬ, йе?)) == сЬ ))юЫеп(паггого(сЬ, йе?)) кййеп(йеб О не гарантируется Однако, хотя часто так и бывает, нельзя дать подобных гарантий для символа, представляемого несколькими значениями в большем наборе символов, но только одним — в меньшем. Например, цифра 7часто имеет несколько различных представлений в большем наборе символов.
Причина в том, что как правило, большие наборы символов содержат неско.лько обычных наборов символов в качестве подмножеств, причем символы из меныпих наборов повторяются для удобства преобразования. Для каждого символа из основного набора (э В.З.З) гарантируется, что ш?йеп(паггош(сЬ Ы, 0)) == сЬ Рй Например: соЦеп(пассосе('~, О)) == 'х' с?эункции паггош() и ш?йеп() соблюдают классификацию символа, когда это возможно.
Например, если ?з(а 1рйа, с), то ?з(а?рйа, паггого(с, 'а')) и ?з(а1рйа, шайеп(с)), при условии что а1рйа является корректной маской для используемой локализации. Г 4. Стандартные фасеты 1005 Главной целью использования фасета с1уре вообще и функций пакготс() и ш!с(еп() в частности является написание кода, осуществляющего ввод/вывод и обработку строк для любого набора символов; то есть мы хотим обеспечить общность кода в отношении наборов символов. Подразумевается, что реализации !оз1 еат решающим образом зависят от описанных в данном разделе средств.