Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Проверить html цвет на валидность

#php #html


Есть поле INPUT, в который вводится цвет вида fff (обязательно без "#" она подставляется
в самом html).

Из него данные передаются в PHP и там в HTML прямо подставляется то значение, как
его правильнее фильтровать?
И сделать чтобы если оно невалидное, то подставлялось стандартное значение?
    


Ответы

Ответ 1



Проверить валидность можно регуляркой. Например такой, так как цвет можно задавать как 3-мя, так 6-ми символами: /^([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?$/i Как-то так: $color; // тут у вас строка с цветом if(preg_match('/^([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?$/i', $color)){ // валидный цвет } else{ // не валидный цвет }

Ответ 2



Экономим на спичках! preg_match() считается медленной функцией. Быстрее проверить длину строки (только 3 или 6), а затем ASCII код каждого символа в строке: = 97 && $code <= 102) continue; // a-f if( $code >= 65 && $code <= 70) continue; // A-F if( $code >= 48 && $code <= 57) continue; // 0-9 return false; } return true; } Ideone с тестами.

Ответ 3



Можно проще: function validate_color($str){ return (($l=strlen($str))==3)||($l==6)) && sscanf($str,"%x", $color); } print(validate_color("AAA")? "цвет валидный": "цвет не валидный"); P.S. Снимаем вопросы по быстродействию: function validate_color_sscan($str){ return ($l=strlen($str)) && (($l==3)||($l==6)) && sscanf($str,"%x", $color); } function test_sscan($str){ for($i=0; $i<2000000; $i++) $v=($l=strlen($str)) && (($l==3)||($l==6)) && sscanf($str,"%x", $color); } function validate_color_preg($str){ return preg_match('/^[A-F0-9]{3}([A-F0-9]{3})?$/i', $str); } function test_preg($str){ for($i=0; $i<2000000; $i++) $v=preg_match('/[a-f0-9]{3}([a-f0-9]{3})?$/i', $str); } print(validate_color_sscan("AAA")? "
цвет валидный": "
цвет не валидный"); print(validate_color_preg("AAA")? "
цвет валидный": "
цвет не валидный"); $time0 = microtime(true); test_sscan($str); $time1 = microtime(true); test_preg($str); $time2 = microtime(true); printf("
test_sscan x 2000000: %d mcs", $time1-$time0); printf("
test_preg x 2000000: %d mcs", $time2-$time1); Результаты: цвет валидный цвет валидный test_sscan x 2000000: 8 mcs test_preg x 2000000: 14 mcs

Ответ 4



preg_match('/^([a-f0-9]{6}|[a-f0-9]{3})$/i', $color)

Ответ 5



Хотелось найти еще какой-либо альтернативный вариант, помимо регулярных выражений. Откопал функцию ctype_xdigit() - проверяет, является ли строка шестнадцатеричным значением (без символа решетки). Не ручаюсь на счет производительности, не пользовался ей. ctype_xdigit('fff'); // true

Зачем нужен встроенный делегат Func?

#c_sharp


При решении очередной проблемы опять сталкнулся со встроенным делегатом Func. Никак
не могу понять его предназначение, как он работает и как устроен. Может кто-то на каком-то
простом примере объяснить что это, для чего используется, как это работает и как этим
пользоваться?
    


Ответы

Ответ 1



Допустим мы имеем метод, который рисует графики различных функций, для простоты - алгебраических, вида y=f(x). Нашему методу все равно какую именно функцию данного вида рисовать, главное чтобы вид функции совпадал с заданным. тогда мы можем определить наш метод следующим образом: public void DrawFunc(Func f) { for(double x = 0.0; x<1.0; x+=0.001) { double y = f(x); //и далее рисуем точки графика } } Теперь для отрисовки графика нам нужно вызвать наш метод и передать ему подходящую функцию. Для Func< double, double> нам подойдет любая функция вида double FuncName(double ParamName), например Math.Sin. Вызов будет выглядеть так: DrawFunc(Math.Sin); Данный делегат, как и аналогичный ему Action используется в основном для быстрого объявления делегатов стандартного вида. Определено несколько отдельных делегатов вида Func< T1,...,T16,TResult>, и Action< T1,...,T16> которые могут принимать до 16-ти параметров (.NET 4+, до 4-х для .NET 3.5), типы которых указываются при объявлении. Кроме этого для Func необходимо указать тип возвращаемого значения TResult, у Action возвращаемое значение всегда void. Больше ничем от обычных делегатов они не отличаются. тут уже обсуждалась очень похожая тема и есть еще немного информации

Ответ 2



В дополнение к правильному ответу @rdorn: Func<> — это по существу (с мелкими отличиями) тип, описывающий функцию. Вы можете передавать в другой метод или класс не только данные, но и код. Для этого вам нужно описать его тип, чтобы его можно было присваивать параметру, записывать в переменные или возвращать из функций. Вот Func<> именно для этого и служит. Пример: // применяет функцию дважды к начальному значению и выводит результат void ApplyTwiceAndPrint(Func f, int value) { int result1 = f(value); int result2 = f(result1); Console.WriteLine(result2); } ApplyTwiceAndPrint(n => n * n, 3); // выводит 81 Как именно это работает внутри? Внутри Func<...> является объектом типа MulticastDelegate, у которого определена функция Invoke(...). Когда вы пишете f(value), компилятор поставляет вместо этого f.Invoke(value), то есть, вызывает метод Invoke. (Да, тут есть немного компиляторного «сахара», которого нету, скажем, у Java.) Внутри объект типа MulticastDelegate хитрым системно-зависимым образом содержит по сути указатель на метод, который и будет вызван в реализации метода Invoke.

Как правильно парсить с помощью AngleSharp?

#c_sharp #html #css #anglesharp


Всем привет! Много тем уже перечитал похожих, но в них в основном какие-то частности
спрашивались. Очень согласен вот с этими словами. Ну, честно говоря, вообще ничего
непонятно. Понял, что информация из html парсится либо через LINQ, либо через CSS селекторы.
С первым вообще не знаком, CSS знаю поверхностно. Но все равно такой вариант мне интуитивно
что ли ближе, поэтому хотелось бы ответы получить в виде CSS селекторов.  

Сразу вопрос: всю ли инфу можно запарсить обоими способами? Или есть только случаи,
когда работает только один из способов? Или же есть случаи, где вообще нельзя?)  

Теперь непосредственно к задаче. Хочу запарсить данные контактов с сайта домофонда.
Например, возьмем вот эту страницу. Парсю всю страницу для начала

var parser = new HtmlParser();
var doc = parser.Parse("ссыль");


Как, например, запарсить имя? Смотрю исходник, вижу, что имя находится в блоке
div class="df_panel". Вроде бы этот блок с уникальным названием, поэтому можно сузить
поиск

var div = doc.QuerySelector("div.df_panel");


Вот тут сразу начинаются вопросы. Сам разобрался, что, если в блоке div указывается
название класса, то пишется так, как приведено. Если, например, div id="test", то уже
запрос по-другому пишется (долго доходило на основе кучу примеров из разных форумов)

var div = doc.QuerySelector("div[id="test"");


Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то
регулярные выражения. Может они аналогичные каким-то другим парсерам, как, например,
написано тут, что AngleSharp очень похож на Fizzler. Но что, если у меня это локально
возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять,
что именно мне писать?  

Ладно, отвлекся. Див ближайший для сужения круга поиска получили. (Опять отвлекусь
- кстати, а как быть, если бы его вообще не было? Можно ли каким-то образом получить
определенные данные, если нет уникальных идентификаторов, посредством которых сужается
постепенно зона поиска нужного значения?). Итого видим, что имя записано в тег заголовка
НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка? Пока на этом вопросы задавать перестану. Буду благодарен за любые объяснения. Желательно очень получить ответы на более общие вопросы (например, по поводу, как я предполагаю, этих регулярных выражений с хелпом или хорошими примерами), тогда может с остальной частью я и сам разберусь.


Ответы

Ответ 1



Самое важное Перво-наперво, вам нужно выучить CSS селекторы. А для лучшего понимания, хотя бы еще основы HTML. Сделать это можно, например, на HTML Academy. Бесплатно. Я бы еще добавил, что никакой магии нет- все выборки AngleSharp это стандартные селекторы CSS, а не что-то необычное. (c) ReinRaus Отвечу на ваш вопрос: Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать? Чтобы понять, что надо писать, повторюсь, вам надо выучить CSS селекторы. Сделать это можно, например, здесь: "Знаете ли вы селекторы?". Приведу здесь краткую выжимку из упомянутой выше статьи: Основные виды селекторов Основных видов селекторов всего несколько: * – любые элементы. div – элементы с таким тегом. #id – элемент с данным id. .class – элементы с таким классом. [name="value"] – селекторы на атрибут (см. далее). :visited – «псевдоклассы», остальные разные условия на элемент (см. далее). Селекторы можно комбинировать, записывая последовательно, без пробела: .c1.c2 – элементы одновременно с двумя классами c1 и c2 a#id.c1.c2:visited – элемент a с данным id, классами c1 и c2, и псевдоклассом visited Отношения В CSS3 предусмотрено четыре вида отношений между элементами. Самые известные вы наверняка знаете: div p – элементы p, являющиеся потомками div. div > p – только непосредственные потомки Есть и два более редких: div ~ p – правые соседи: все p на том же уровне вложенности, которые идут после div. div + p – первый правый сосед: p на том же уровне вложенности, который идёт сразу после div (если есть). Селекторы атрибутов На атрибут целиком: [attr] – атрибут установлен, [attr="val"] – атрибут равен val. На начало атрибута: [attr^="val"] – атрибут начинается с val, например value. [attr|="val"] – атрибут равен val или начинается с val-, например равен val-1. На содержание: [attr*="val"] – атрибут содержит подстроку val, например равен myvalue. [attr~="val"] – атрибут содержит val как одно из значений через пробел. Например: [attr~="delete"] верно для edit delete и неверно для undelete, а еще неверно для no-delete. На конец атрибута: [attr$="val"] – атрибут заканчивается на val, например равен myval. Где попрактиковаться? CSS Diner - здесь нужно выбирать элемент, соответствующий указанному CSS правилу. HTML Academy - здесь можно изучить основы верстки. htmlbook - справочник по css селекторам и html тегам. Ответы на остальные вопросы Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то регулярные выражения. Это не регулярные выражения, а CSS селекторы. Об этом я написал выше. Можно ли каким-то образом получить определенные данные, если нет уникальных идентификаторов, посредством которых сужается постепенно зона поиска нужного значения? Да, комбинируя дочерние элементы по любому признаку. Например, первый потомок в родителе (* > *:first-child), точно второй по счету элемент p внутри своего родителя (p:nth-child(2)), не пустой a элементы (a:not(:empty)) и так далее. Итого видим, что имя записано в тег заголовка
НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка? Если я правильно понял, и имеется в виду значение, не обернутое в какой-либо тег, то все равно ответ будет – да. Можно выполнить поиск по тексту. Для этого конкретного случая решение в виде селектора будет таким: h6[itemprop="name"] как только не пробовал. Не парсит с .df_panel Ваш код из комментариев использует метод QuerySelector, который, как я понимаю, выбирает первый элемент с указанным селектором. Первый .df_panel из шести на странице не содержит элемента h6. Поэтому у вас ничего и не находит. Еще раз подчеркну: на странице шесть элементов .df_panel. Код для выборки нужного вам элемента var seller = doc.QuerySelector("[itemprop='seller']"); var name = seller.QuerySelector("[itemprop='name']").Text();

Ответ 2



Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать? Выше ответили про то, что вам нужно знать css селекторы, однако поскольку вопрос светится в поисковиках (вопросов на ru-so не так много) - допишу ещё полезную ссылку по теме. В официальных репозиториях AngleSharp на гитхабе есть демо-приложение.

std::next vs std::advance

#cpp


Почему std::next дефолтно продвигает на 1, а std::advance - нет? 
    


Ответы

Ответ 1



Я уже делал такое предложение комитету стандартизации по C++. Я описал данное несоответствие на своем форуме в теме std::advance и std::bitset - два простых предложения по стандарту C++ Номер этого предложения №4369. К сожалению я не отслеживал судьбу этого предложения. Формально предварительно в обсуждении оно было одобрено, но, как всегда, в комитете есть люди которые считают лишь собственные предложения самыми важными и ревниво относятся к другим предложениям. Поэтому я сейчас не в курсе, какова судьба моего предложения. Но явных причин не делать аргумент по умолчанию для второго параметра я не вижу и не встречал какие-либо серьезные возражения со стороны других оппонентов.

Ответ 2



Эти функции служат несколько разным целям и появились по совершенно разным причинам. std::advance - функция старая (С++98), которая предназначалась для унификации итераторов разных категорий в generic алгоритмах, и в первую очередь в тех ситуациях, когда итератор надо отодвинуть более чем на один шаг. С отодвиганием ровно на один шаг справлялись операторы ++ и --. std::advance была выполнена именно в виде именованной функции (а не перегрузки операторов += или -=) именно для того, чтобы привлечь внимание пользователя к потенциально неэффективной операции и тем самым постараться исключить ее непреднамеренное использование. Аналогичные причины обусловили появление "парной" явной функции std::distance. std::next и std::prev - функции новые (С++11), созданные в частности для того, чтобы инкапсулировать идиому получения соседнего итератора без модификации текущего. Учитывая, что в общем случае к итератору не применима бинарная операция +, нельзя просто взять и прибавить к итератору 1 It it; ... foo(it + 1); // в общем случае - не сработает Для итераторов класс-типов в такой ситуации работает компактный вариант foo(++It(it)); но он неприменим к итераторам фундаментальных типов, что в generic контекстах заставляет заводить дополнительную именованную переменную, т.е. выписывать что-то вроде It it_next = it; foo(++it_next); Это более громоздко, чем хотелось бы, и вводит в код ненужную именованную переменную. Функция std::advance, если обратить внимание на особенности ее интерфейса, тут никак помочь нам не может. Вот тут-то и приходят на помощь функции std::next и std::prev, которые скрывают подобные детали. При этом их наиболее востребованным назначением/употреблением является именно получение соседнего итератора. А возможность указать расстояние - лишь естественное расширение этой функциональности. Другими словами, ответ на ваш вопрос в историческом ключе звучит просто: std::advance была создана именно для сдвига итератора более чем на 1 шаг, а std::next и std::prev заведены в первую очередь для сдвига ровно на 1 шаг. Также учитывая, что std::advance может работать в обоих направлениях, было бы странно сейчас навязывать ей именно +1 в качестве умолчательного аргумента. Вполне может быть, что если бы изначально в C++98 функцию std::advance ввели именно с интерфейсом template< class InputIt, class Distance > InputIt advance( InputIt it, Distance n ); (т.е. с передачей и возвратом итератора "по значению", а не с передачей модифицируемого итератора "по ссылке"), то сегодня особой необходимости в std::next и std::prev так и не возникло бы. А если бы эти функции и появились бы, то возможно без параметра "расстояния".

Ответ 3



Почему std::next дефолтно продвигает на 1, а std::advance - нет? Потому как std::next как и std::prev явно указывают направление модификации. И наличие дефолтного значения - лишь уточнение шага. Приписать же дефолтную модификацию для std::advance смысла нет, так как для данной функции позитивное и негативное смещения "равно-значимы". Если прописать шаг, то это автоматически приравнивается и к прописке дефолтного направления модификации, что не будет соответствовать аббревиатуре функции.

Как работает CancellationToken в TaskFactory.StartNew Method (Action, CancellationToken)?

#c_sharp #net #task


Делаю:

Task.Factory.StartNew(() =>Method(),ct)


В другом месте вызываю tokenSource.Cancel();, но ничего не происходит.

Мне казалось, что такая перегрузка должна полностью задачу снимать.

Получается, что нужно токен передавать непосредственно в сам метод и там производить
анализ?

Можно ли как-нибудь отменить задачу, непередавая во внутрь токен?
    


Ответы

Ответ 1



Смотрите. Вы не можете «отменить» уже бегущий код — по тем же причинам, по которым вы не можете «убить» бегущий thread. Поэтому код, запускаемый через Task.Run, добежит до конца, если только он сам не будет анализировать токен и не отменит себя сам. Однако, таск не будет запущен, если токен находится уже в отменённом состоянии. Поскольку запуск Task'а — расходная штука, это неплохая оптимизация. Кроме того, таск при этом будет ассоциирован с этим токеном, и если код в Method бросит исключение через token.ThrowIfCancellationRequested, это исключение будет считаться относящимся к таску. Тем самым таск будет завершён в состоянии Cancelled, а не Faulted. Источник информации: https://social.msdn.microsoft.com/Forums/en-US/c2f614f6-c96c-4821-84cc-050b21aaee45/taskfactorystartnew-cancellation-token-parameter?forum=parallelextensions Воспроизводящий пример: async Task Run() { var cts = new CancellationTokenSource(); var ct = cts.Token; var t = Task.Run((Action)(() => // каст нужен! пояснение в конце ответа { while (true) { ct.ThrowIfCancellationRequested(); Thread.Sleep(200); } }), cts.Token); await Task.Delay(400); cts.Cancel(); try { await t; } catch (TaskCanceledException ex) { Console.WriteLine($"caught TaskCanceledException, task status = {t.Status}"); } catch (OperationCanceledException ex) { Console.WriteLine($"caught OperationCanceledException, task status = {t.Status}"); } } Этот код попадает в catch (OperationCanceledException ex), и состояние таска — Canceled. А если убрать токен, то мы попадаем также в catch (OperationCanceledException ex), но состояние — Faulted. В этом случае рантайм считает, что произошла не отмена таска, а просто какое-то постороннее исключение. (В TaskCanceledException мы попадаем, если таск был отменён до запуска.) (Ошибка в предыдущей версии кода была в том, что не было явного приведения к Action [которое практически никогда не нужно!], и ввиду бесконечного цикла внутри типовыводитель не мог решить, это перегрузка с Action или перегрузка с Func! В результате он выбирал не то, что нужно, и рантайм считал, что отменён не таск, а процесс его создания.)

Ответ 2



Да, токен необходимо передавать в метод, и там периодически вызывать ThrowIfCancellationRequested(). Однако, это не отменяет необходимости передавать его вторым параметром StartNew(). Это делается на тот случай, если отмена операции запрошена раньше чем начал выполняться ваш метод (а так же для того, чтобы связать таск с токеном). Примерно так: var cts = new CancellationTokenSource(); Task.Factory.StartNew(() => { while (true) { cts.Token.ThrowIfCancellationRequested(); Console.WriteLine("I'm working..."); } }, cts.Token); cts.CancelAfter(10); Если была запрошена отмена, то метод ThrowIfCancellationRequested() кинет OperationCanceledException. При желании, его можно поймать и сообщить юзеру, что операция успешно отменена, например. Если хочется, то можно обходиться без эксепшена, а просто в методе проверять: if (token.IsCancellationRequested) { /*выходим из метода*/ } Но тогда сама задача не будет знать о том, что её отменили. В свойстве Status у неё будет TaskStatus.RanToCompletion вместо TaskStatus.Canceled. UPD: Дополнительный материал по теме: https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

Объясните этот синтаксис пожалуйста

#c #структуры


Нет, правда. Поверхностно я знаю C но это... новый синтаксис C99 наверное:

struct node {
    int payload;
    int height;
    struct node *kid[2];
} dummy = {0, 0, {&dummy, &dummy}}, *nnil = &dummy;
// internally, nnil is the new nul


Что вот это значит?:


Создать тип struct node node (оказывается имя типа всё-таки struct node) 
typedef struct node dumy Оказывается: объявить (глобальную?) переменную dummy содержащую
помимо прочего массив состоящий из двух указателей на саму себя
, => node* nnil = опять указатель на эту dummy


Я прав? Это шо за синтаксис такой? C99? (смайлик "я в ужасе")
    


Ответы

Ответ 1



struct node { Объявили структуру } dummy Создали переменную типа struct node = {0, 0, Первые два поля переменной dummy - нули (dummy.payload = dummy.height = 0) {&dummy, &dummy}} Элементам массива kid (указателям) присвоили адреса переменной dummy (dummy.kid[0] = dummy.kid[1] = &dummy) , *nnil Создали ещё одну переменную - указатель на переменную типа struct dummy = &dummy; Присвоили ей адрес переменной dummy Всё, никаких хитростей, чистый C безо всяких наворотов.

Ответ 2



В этой конструкции сразу же объявляется структура, объект этой структуры и указатель на объект этой структуры. Чтобы это объявление struct node { int payload; int height; struct node *kid[2]; } dummy = {0, 0, {&dummy, &dummy}}, *nnil = &dummy; было более понятным, вы можете его разбить на несколько объявлений. Исходное объявление эквивалентно следующим объявлениям. struct node { int payload; int height; struct node *kid[2]; }; struct node dummy = {0, 0, {&dummy, &dummy}}; struct node *nnil = &dummy; То есть объявляется структура с именем struct node. Затем объявляется объект этой структуры с именем dummy и его поля, как объекта структуры, инициализируются соответствующими значениями. Чтобы это объявление было еще более понятным, вы можете даже его переписать в C99 как struct node dummy = { .payload = 0, .height = 0, .kid = { [0] = &dummy, [1] = &dummy }}; В этом объявлении объекта dummy его член данных kid, который представляет собой массив указателей, инициализируется адресом самого объекта dummy. И, наконец, в третьем объявлении объявляется указатель с именем nnil на объект dummy

Как отличить текст в файле с обычной кодировкой от Unicode?

#cpp #windows #unicode #текст


Нужно прочесть текстовый файл. Как узнать, закодирован таблицей символов (однобайтовых),
или в файле содержится текст в формате Unicode (16-ти битные символы)?
    


Ответы

Ответ 1



Файл всегда содержит байты. Иногда содержимое файла можно декодировать в текст, используя выбранную кодировку такую как cp1251, cp866, utf-8, или utf-16le. На Windows, файлы, закодированные в utf-16, к сожалению иногда называют Unicode (что вводит в заблуждение: Unicode—это не кодировка). utf-16 это всего лишь одна из многих кодировок, которую можно использовать, чтобы закодировать текст (Unicode) в байты: байты = юникод_текст.encode(кодировка) юникод_текст = байты.decode(кодировка) Файлы, содержащие текст, закодированный в utf-8, utf-16, utf-32 и других кодировках, могут содержать в начале специальную последовательность байт (U+FEFF символ BOM, закодированный в соответствующей кодировке), которая идентифицирует эти кодировки. Если файл следует этому соглашению, то достаточно несколько первых байт из файла (в двоичном режиме открытого) сравнить с вариантами BOM, чтобы определить соответствующую кодировку. В общем случае нет гарантированного на 100% способа определить кодировку файла (хотя некоторые кодировки могут быть более вероятны чем другие и может быть API, которое пытается угадать кодировку, такое как: IsTextUnicode() с IS_TEXT_UNICODE_STATISTICS). Пример: "Bush hid the facts" текст, закодированный в ascii кодировке, мог некоторыми приложениями интерпретироваться как текст в utf-16le кодировке, приводя к кракозябрам.

Ответ 2



Зависит от соглашения, в котором записан текстовый файл. Текстовый поток, записанный в формате Unicode может начитаться с BOM - Byte Order Mark, т.е. например с магических байтов FF, FE для UTF-16 Little Endian. А в отсутствие каких-либо соглашений - только анализ текста с элементами гадания на кофейной гуще.

Ответ 3



Простая на первый взгляд задача, но выполнить её оказывается не просто. С++ обладает достаточной гибкостью, как язык среднего уровня, поэтому требуется исчерпывающее знание вопроса для эффективной реализации задачи. Поделюсь тем что выяснил.Чтобы правильно прочесть файл нужно сначала посмотреть, есть ли в начале файла Маркер последовательности (тут точнее). Если есть маркер, его нужно определить. Если маркера нет, как выше уже было сказано, нужно искать другой алгоритм определения кодировки.Я тут целиком и полностью полагаюсь на IsTextUnicode, если маркера нет:BYTE *pBuf;size_t szRead, szBOM; // к-во прочитанных в файле байт и к-во байт маркераenum Unicode eUnicode;LPTSTR pszText;...// определяю, есть ли в тексте маркер (ручная работа)szBOM = IsUnicodeRaw(pBuf, szRead, &eUnicode);// вызов библиотечной ф-ции IsTextUnicode после собственной проверкиif(eUnicode != utf_16LE && ((szRead - szBOM) % 2 || !IsTextUnicode(pBuf + szBOM, (int) (szRead - szBOM), NULL))){ BYTE *pb = new BYTE[(szRead - szBOM + 1) * sizeof(wchar_t)]; unsigned int nCP = (eUnicode == utf_8) ? CP_UTF8 : (eUnicode == utf_7) ? CP_UTF7 : CP_ACP; if (!MultiByteToWideChar(nCP, (nCP == CP_ACP) ? MB_PRECOMPOSED : 0, (LPCSTR) (pBuf + szBOM), (int) (szRead - szBOM), (LPWSTR) pb, (int) (szRead - szBOM))) { // ошибка... } delete[] pBuf; pszText = (LPTSTR) (pszBuf = pb)}else pszText = (LPTSTR) (pszBuf + szBOM);После того как выяснил наличие маркера в ф-ции IsUnicodeRaw, обращаюсь к IsTextUnicode без маркера. Работает с UTF-8, с UTF-7 нужно разбираться - там последние 2 бита маркера являются частью следующего за маркером символа. ANSI-текст так же нормально кодирует в двухбайтовый.Wind'а предпочитает UTF-8 и UTF-16LE. Перед тем как записать текст, его нужно либо перекодировать в ANSI ф-цией WideCharToMultibyte, либо в начало файла записать маркер кодировки UTF-8 или UTF-16LE, чтобы потом также прочесть.

Ответ 4



Кажется, нашёл. Ф-ция IsTextUnicode из Advapi32.dll ответит на поставленный вопрос.