c ++ windows: Есть ли способ конвертировать из _UNICODE_STRING в std :: string? [Дубликат]

Хотя это не решение для списков напрямую, numpy действительно сияет для такого рода вещей:

import numpy as np
values = np.array([1,2,3,1,2,4,5,6,3,2,1])
searchval = 3
ii = np.where(values == searchval)[0]

возвращает:

ii ==>array([2, 8])

Это может быть значительно быстрее для списки (массивы) с большим количеством элементов по сравнению с некоторыми другими решениями.

645
задан Rapptz 31 January 2013 в 23:33
поделиться

11 ответов

Я рекомендую избегать std::wstring в Windows или в другом месте, за исключением случаев, когда это требуется интерфейсом, или где-нибудь рядом с вызовами Windows API и соответствующими преобразованиями кодировки в качестве синтаксического сахара.

Мой взгляд обобщен в http://utf8everywhere.org , из которых я являюсь соавтором.

Если ваше приложение не ориентировано на API, например. в основном приложение UI, рекомендуется хранить строки Unicode в std :: string и кодироваться в UTF-8, выполняя преобразование около вызовов API. Преимущества, изложенные в статье, перевешивают явное раздражение конверсии, особенно в сложных приложениях. Это вдвойне подходит для многоплатформенной и библиотечной разработки.

И теперь, отвечая на ваши вопросы:

  1. Несколько слабых причин. Он существует по историческим причинам, где считается, что широкополосные каналы являются надлежащим способом поддержки Unicode. Теперь он используется для интерфейса API, которые предпочитают строки UTF-16. Я использую их только в непосредственной близости от таких вызовов API.
  2. Это не имеет никакого отношения к std :: string. Он может содержать любую кодировку, которую вы вкладываете в нее. Вопрос только в том, как вы относитесь к его содержанию. Моя рекомендация - UTF-8, поэтому он сможет корректно хранить все символы юникода. Это обычная практика в Linux, но я думаю, что Windows также должны это делать.
  3. Нет.
  4. Широкий символ - запутанное имя. В первые дни Unicode существовало убеждение, что символ может быть закодирован в два байта, отсюда и название. Сегодня это означает «любая часть персонажа, длина которой составляет два байта». UTF-16 рассматривается как последовательность таких пар байтов (aka Wide characters). Символ в UTF-16 принимает одну или две пары.
48
ответ дан amn 19 August 2018 в 03:26
поделиться
  1. Если вы хотите сохранить символы «wide» (Unicode).
  2. Да: 255 из них (исключая 0).
  3. Да.
  4. Вот вступительная статья: http://www.joelonsoftware.com/articles/Unicode.html
3
ответ дан ChrisW 19 August 2018 в 03:26
поделиться
  • 1
    std :: string может содержать 0 просто отлично (просто будьте осторожны, если вы вызываете метод c_str ()) – Mr Fooz 31 December 2008 в 05:40
  • 2
    И, строго говоря, символ не может быть 8 бит. :) Ваша ссылка в №4 является обязательным для чтения, но я не думаю, что она отвечает на вопрос. Широкий персонаж не имеет ничего общего с юникодом. Это просто более широкий характер. (Насколько шире зависит от ОС, но обычно 16 или 32 бит) – jalf 31 December 2008 в 13:08
  • 3
    – Pavel Radzivilovsky 5 January 2011 в 13:43

Итак, каждый читатель здесь должен иметь четкое представление о фактах, ситуации.

Мое прагматическое заключение шокирует просто: все, что C ++ (и STL) «кодирование символов» существенно нарушено и бесполезно. Виноват это в Microsoft или нет, это все равно не поможет.

Мое решение, после глубокого расследования, много разочарования и последующего опыта заключается в следующем:

  1. accept , что вы должны нести ответственность за свой материал для кодирования и преобразования (и вы увидите, что большая часть его довольно тривиальная)
  2. используют std :: string для любых кодированных строк UTF-8 (только a typedef std::string UTF8String)
  3. принимают, что такой объект UTF8String является просто тупым, но дешевым контейнером. Никогда не обращайтесь к ним и / или не манипулируйте ими непосредственно (без поиска, замены и т. Д.). Вы могли бы, но вы действительно просто действительно не хотите тратить свое время на написание алгоритмов манипуляции текста для многобайтовых строк! Даже если другие люди уже делали такие глупые вещи, не делайте этого! Будь как будет! (Ну, есть сценарии, где это имеет смысл ... просто используйте библиотеку ICU для них).
  4. использовать std :: wstring для кодированных строк UCS-2 (typedef std::wstring UCS2String) - это компромисс , и концессию на беспорядок, введенный WIN32 API). UCS-2 является достаточным для большинства из нас (подробнее об этом позже ...).
  5. использует экземпляры UCS2String всякий раз, когда требуется доступ к символьным символам (чтение, манипулирование и т. Д.). Любая обработка на основе символов должна выполняться в N-многобайтовом представлении. Это просто, быстро и легко.
  6. добавить две служебные функции для преобразования back & amp; между UTF-8 и UCS-2:
    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );
    

Преобразования просты, Google должен помочь здесь ...

Вот и все. Используйте UTF8String везде, где важна память, и для всех входов / выходов UTF-8. Используйте UCS2String везде, где строка должна анализироваться и / или обрабатываться. Вы можете конвертировать между этими двумя представлениями в любое время.

Альтернативы & amp; Улучшения

  • преобразования из & amp; однобайтовые кодировки символов (например, ISO-8859-1) могут быть реализованы с помощью простых таблиц перевода, например. const wchar_t tt_iso88951[256] = {0,1,2,...}; и соответствующий код для преобразования в & amp; из UCS2.
  • , если UCS-2 недостаточно, чем переключиться на UCS-4 (typedef std::basic_string<uint32_t> UCS2String)

ICU или другие библиотеки Unicode?

Для продвинутых материалов.

35
ответ дан Frunsi 19 August 2018 в 03:26
поделиться
  • 1
    Данг, нехорошо знать, что родной поддержки Unicode там нет. – Mihai Danila 15 December 2013 в 18:59
  • 2
    @Frunsi, мне любопытно узнать, пробовали ли вы Glib :: ustring, и если да, то каковы ваши мысли? – Caroline Beltran 19 September 2014 в 20:44
  • 3
  • 4
    Поиск, замена и т. Д. Отлично работает на строках UTF-8 (часть байтовой последовательности, представляющая символ, никогда не может быть неверно истолкована как другой символ). На самом деле, UTF-16 и UTF-32 не делают это проще: все три кодирования являются многобайтовыми кодировками на практике, потому что воспринимаемый пользователем символ (кластер графем) может быть любым количеством кодов unicode долгое время! Прагматичным решением является использование UTF-8 для всего и преобразование в UTF-16 только при работе с Windows API. – Daniel 17 October 2014 в 11:49
  • 5
    @Frunsi: поиск и замена выполняются так же хорошо, как UTF-8, как и UTF-32. Именно потому, что надлежащая обработка текста в формате Unicode должна иметь дело с символами с несколькими кодами, так как использование кодировки с переменной длиной, например UTF-8, не делает сложной обработку строк. Поэтому просто используйте UTF-8 везде. Стандартные функции строчной строки C отлично работают на UTF-8 (и соответствуют порядковым сравнениям в строке Unicode), и если вам нужно что-то большее, чем знание языков, вам все равно придется звонить в библиотеку Unicode, UTF-16/32 не может спасти вас от этого. – Daniel 23 October 2014 в 11:16
  1. , когда вы хотите использовать строки Unicode, а не только ascii, полезно для интернационализации
  2. да, но это не очень хорошо работает с 0
  3. , не зная о каких-либо что не
  4. широкий символ является специфичным для компилятора способом обработки представления фиксированной длины символа Юникода, для MSVC это 2-байтовый символ, для gcc я понимаю, что это 4 байта. и +1 для http://www.joelonsoftware.com/articles/Unicode.html
1
ответ дан Greg Domjan 19 August 2018 в 03:26
поделиться
  • 1
    2. Строка std :: может содержать символ NULL. Он также может содержать utf-8 и широкие символы. – user 31 December 2008 в 05:29
  • 2
    @Juan: Это снова запутало меня. Если std :: string может содержать символы юникода, что особенность в std :: wstring? – user 31 December 2008 в 05:33
  • 3
    @Appu: std :: string может содержать символы Unicode UTF-8. Существует ряд стандартов Unicode, предназначенных для различной ширины символов. UTf8 имеет ширину 8 бит. Также есть UTF-16 и UTF-32 с шириной 16 и 32 бит соответственно – Greg D 31 December 2008 в 05:40
  • 4
    С помощью std :: wstring. Каждый символ Юникода может быть одним wchar_t при использовании кодировок с фиксированной длиной. Например, если вы решили использовать joel на программном подходе в качестве ссылок Greg. Тогда длина wstring - это точно число символов в кодировке Unicode. Но это занимает больше места – user 31 December 2008 в 05:43
  • 5
    Я не сказал, что он не может содержать 0 '\ 0', и то, что я имел в виду, не очень хорошо работает, так это то, что некоторые методы могут не дать ожидаемого результата, содержащего все данные wstring. Настолько суровым на пустые голоса. – Greg Domjan 31 December 2008 в 05:53
889
ответ дан Jasper 19 August 2018 в 03:26
поделиться
  1. Если вы хотите иметь широкие символы, хранящиеся в вашей строке. wide зависит от реализации. Visual C ++ по умолчанию имеет значение 16 бит, если я правильно помню, в то время как настройки GCC по умолчанию зависят от цели. Здесь 32 бита. Обратите внимание: wchar_t (широкий тип символа) не имеет ничего общего с юникодом. Просто гарантируется, что он может хранить все элементы самого большого набора символов, поддерживаемые реализацией его локалями, и, по крайней мере, до тех пор, пока char. Вы можете сохранить строки unicode в std::string с помощью кодировки utf-8. Но это не будет понимать смысл кодов Unicode. Таким образом, str.size() не даст вам количество логических символов в вашей строке, а просто количество элементов char или wchar_t, хранящихся в этой строке / wstring. По этой причине пользователи обложек gtk / glib C ++ разработали класс Glib::ustring , который может обрабатывать utf-8. Если ваш wchar_t имеет длину 32 бита, вы можете использовать utf-32 в качестве кодировки в Юникоде, и вы можете хранить строки с кодом юникода и с использованием фиксированного (utf-32 фиксированной длины). Это означает, что функция s.size() вашей wstring будет , затем вернет правильное количество логических символов wchar_t элементов и .
  2. Да, char всегда имеет длину не менее 8 бит, что означает, что он может хранить все значения ASCII.
  3. Да, все основные компиляторы поддерживают его.
23
ответ дан Johannes Schaub - litb 19 August 2018 в 03:26
поделиться
  • 1
    Мне любопытно, что №2. Я думал, что 7 бит тоже будут технически обоснованными? Или требуется, чтобы иметь возможность хранить что-нибудь за 7-разрядными символами ASCII? – jalf 31 December 2008 в 13:11
  • 2
    да, jalf. c89 указывает минимальные диапазоны для базовых типов в своей документации limits.h (для unsigned char, это 0..255 мин) и чистая двоичная система для целых типов. он следует за char, unsigned char и signed char имеет минимальные длины бит 8. c ++ наследует эти правила. – Johannes Schaub - litb 31 December 2008 в 13:26
  • 3
    «Это означает, что ваша функция s.size () вашей wstring вернет правильное количество элементов и логических символов wchar_t. & quot; Это не совсем точно, даже для Unicode. Точнее сказать, кодовый пример, чем «логический символ», даже в UTF-32 данный символ может состоять из нескольких кодовых точек. – Logan Capaldo 16 May 2010 в 18:26
  • 4
    Вы, по сути, говорите, что C ++ не имеет встроенной поддержки набора символов Unicode? – Mihai Danila 15 December 2013 в 18:56
  • 5
    & quot; Но он не поймет значение кодов Unicode. & quot; В окнах также нет std::wstring. – Deduplicator 8 January 2015 в 23:20

Хороший вопрос! Я думаю, что DATA ENCODING (иногда CHARSET также участвует) является MEMORY EXPRESSION MECHANISM, чтобы сохранить данные в файл или передавать данные по сети, поэтому я отвечаю на этот вопрос следующим образом:

1.Когда я должен использовать std: : wstring over std :: string?

Если платформа программирования или функция API являются однобайтными, и мы хотим обрабатывать или анализировать некоторые данные в формате unicode, например, читать из файла Windows .REG или сети Windows 2-байтовый поток, мы должны объявить переменную std :: wstring, чтобы упростить их обработку. например: wstring ws = L "中国 a" (6 октетов: 0x4E2D 0x56FD 0x0061), мы можем использовать ws [0] для получения символов '中' и ws [1] для получения символов '国' и ws [2] get character 'a' и т. д.

2.Can std :: string содержит весь набор символов ASCII, включая специальные символы?

Да. Но обратите внимание: American ASCII означает, что каждый октет 0x00 ~ 0xFF для одного символа, включая печатный текст, такой как «123abc & amp; * _ & amp;» и вы сказали специальный, в основном напечатайте его как «.». избегайте запутывания редакторов или терминалов. И некоторые другие страны расширяют свою собственную кодировку «ASCII», например. Китайцы, используют 2 октета для обозначения одного персонажа.

3.Is std :: wstring поддерживается всеми популярными компиляторами C ++?

Возможно, или в основном. Я использовал: VC ++ 6 и GCC 3.3, YES

4. Что такое «широкий символ»?

Широкий символ в основном указывает использование 2 октетов или 4 октета всех стран. 2 октета UCS2 представляет собой репрезентативную выборку, а далее, например, Английский 'a', его память составляет 2 октета 0x0061 (vs в ASCII 'a - 1 октет 0x61)

0
ответ дан Leiyi.China 19 August 2018 в 03:26
поделиться
0
ответ дан Phil Rosenberg 19 August 2018 в 03:26
поделиться

1) Как упоминалось Грегом, wstring полезна для интернационализации, то есть когда вы будете выпускать свой продукт на других языках, кроме английского

4) Проверьте это для широкого символа http: / /en.wikipedia.org/wiki/Wide_character

1
ответ дан Raghu 19 August 2018 в 03:26
поделиться

Приложения, которые не удовлетворяются только 256 различными символами, имеют варианты использования широких символов (более 8 бит) или кодирования переменной длины (многобайтовая кодировка в терминологии C ++), таких как UTF-8. Широким символам обычно требуется больше места, чем кодирование с переменной длиной, но они быстрее обрабатываются. Многоязычные приложения, которые обрабатывают большие объемы текста, обычно используют широкие символы при обработке текста, но преобразуют его в UTF-8, когда хранят его на диске.

Единственное отличие между string и wstring - тип данных символов, которые они хранят. Строка хранит char s, размер которой должен быть не менее 8 бит, поэтому вы можете использовать строки для обработки, например. ASCII, ISO-8859-15 или UTF-8. В стандарте ничего не говорится о наборе символов или кодировке.

Практически каждый компилятор использует набор символов, первые 128 символов которого соответствуют ASCII. Это также относится к компиляторам, использующим кодировку UTF-8. Важное значение, которое следует учитывать при использовании строк в UTF-8 или какой-либо другой кодировке переменной длины, состоит в том, что индексы и длины измеряются в байтах, а не в символах.

Тип данных wstring wchar_t, размер которого не определен в стандарте, за исключением того, что он должен быть как минимум равным char, обычно 16 бит или 32 бита. wstring может использоваться для обработки текста в реализации, определенной широкосимвольной кодировкой. Поскольку кодировка не определена в стандарте, преобразовать между строками и wstrings непросто. Нельзя предположить, что wstrings также будет иметь кодировку с фиксированной длиной.

Если вам не нужна поддержка нескольких языков, вам может быть хорошо, если вы используете только обычные строки. С другой стороны, если вы пишете графическое приложение, часто бывает, что API поддерживает только широкие символы. Тогда вы, вероятно, захотите использовать те же самые широкие символы при обработке текста. Имейте в виду, что UTF-16 является кодировкой переменной длины, что означает, что вы не можете считать length(), чтобы вернуть количество символов. Если API использует кодировку с фиксированной длиной, такую ​​как UCS-2, обработка становится легкой. Преобразование между широкими символами и UTF-8 трудно сделать переносимым образом, но, опять же, API вашего пользовательского интерфейса, вероятно, поддерживает преобразование.

2
ответ дан Seppo Enarvi 19 August 2018 в 03:26
поделиться
  • 1
    Итак, перефразируя первый абзац: для приложения, требующего более 256 символов, необходимо использовать многобайтовое кодирование или, возможно, многобайтовое кодирование. – Deduplicator 10 October 2015 в 12:44
  • 2
    Как правило, 16 и 32-битные кодировки, такие как UCS-2 и UCS-4, не называются многобайтовыми кодировками. Стандарт C ++ различает многобайтовые кодировки и широкие символы. Широкое представление символа использует фиксированное число (обычно более 8) бит на символ. Кодировки, которые используют один байт для кодирования наиболее распространенных символов и несколько байтов для кодирования остальной части набора символов, называются многобайтовыми кодировками. – Seppo Enarvi 12 October 2015 в 21:16
  • 3
    Извините, небрежный комментарий. Должен иметь указанную кодировку переменной длины. UTF-16 является кодировкой переменной длины, как UTF-8. Притворство это не идея bad . – Deduplicator 12 October 2015 в 21:23
  • 4
    Неплохо подмечено. Нет причин, по которым wstrings нельзя было использовать для хранения UTF-16 (вместо UCS-2), но тогда удобство кодирования фиксированной длины теряется. – Seppo Enarvi 12 October 2015 в 22:13

Когда вы НЕ используете широкие символы?

Когда вы пишете код до 1990 года.

Очевидно, я переворачиваюсь, но на самом деле это 21-й век. 127 символов уже давно перестали быть достаточными. Да, вы можете использовать UTF8, но зачем беспокоиться о головных болях?

-4
ответ дан user 19 August 2018 в 03:26
поделиться
  • 1
    Хуан: Вы имеете в виду, что std :: string может содержать все символы Unicode, но длина будет сообщаться неправильно? Есть ли причина, по которой сообщается о неправильной длине? – user 31 December 2008 в 05:35
  • 2
  • 3
    (Зависит от Windows) Большинство функций ожидают, что строка с байтами - ASCII, а 2 байта - Unicode, более старые версии MBCS. Это означает, что если вы храните 8-битный юникод, вам придется преобразовать в 16-разрядный юникод, чтобы вызвать стандартную функцию Windows (если только вы не используете только часть ASCII). – Greg Domjan 31 December 2008 в 05:58
  • 4
    @dave: Я не знаю, какая головная боль создает UTF-8, которая больше, чем у Widechars (UTF-16). в UTF-16 у вас также есть многосимвольные символы. – Pavel Radzivilovsky 29 December 2009 в 17:08
  • 5
    Мало того, что std :: string сообщит длину неправильно, но также выведет неправильную строку. Если какой-то символ Юникода представлен в UTF-8 как несколько байтов, которые std :: string считает своими собственными символами, то ваши типичные процедуры управления строкой std :: string, вероятно, выводят несколько странных символов, которые являются результатом неправильного толкования одного символа правильный характер. – Mihai Danila 15 December 2013 в 19:01
  • 6
    Я предлагаю изменить ответ, чтобы указать, что строки следует рассматривать как только контейнеры с байтами, и, если байты представляют собой некоторую кодировку Unicode (UTF-8, UTF-16, ...), тогда вы должны использовать определенные библиотеки, которые понимают что. Стандартные API-интерфейсы на основе строк (длина, подстрока и т. Д.) Будут терпеть неудачу с многобайтовыми символами. Если это обновление будет сделано, я удалю свой downvote. – Mihai Danila 7 October 2014 в 15:19
  • 7
    Проблема в том, что если вы где-нибудь, кроме англоговорящей страны, вы ДОЛЖНЫ использовать wchar_t. Не говоря уже о том, что некоторые алфавиты имеют больше символов, чем вы можете поместиться в байт. Мы были там, в DOS. Codepage шизофрения, нет, спасибо, не более .. – Swift - Friday Pie 27 November 2016 в 00:02
  • 8
    @Swift Проблема с wchar_t заключается в том, что ее размер и значение специфичны для ОС. Это просто сводит старые проблемы с новыми. В то время как char является char независимо от ОС (по крайней мере, на подобных платформах). Поэтому мы могли бы просто использовать UTF-8, упаковать все в последовательности из char s и заплакать, как C ++ оставляет нас полностью самостоятельно без каких-либо стандартных методов измерения, индексации, поиска и т. Д. В таких последовательностях. – underscore_d 21 May 2017 в 14:16
  • 9
    @underscore_d То, что вы описываете, является наименьшей из проблем, если вы код на C ++. Широкий характер wchat_t является фундаментальным типом в C ++, но не в C, но его двоичное представление не определено платформой, как вы описываете, это runtime . Таким образом, символ может быть 1 байт или 2 байта (по крайней мере) в зависимости от того, какая фактическая строка хранится. Unicode UTF-16 - это символы фиксированного размера. Thing is wchar_t - тип, поддерживаемый определенной платформой на уровне имен файловых систем (включая окна), в то время как на других платформах используются многобайтовые символы – Swift - Friday Pie 21 May 2017 в 14:34
  • 10
    @Swift. Кажется, у вас это полностью назад. wchar_t - тип данных с фиксированной шириной, поэтому массив из 10 wchar_t всегда будет занимать байты платформы sizeof(wchar_t) * 10. И UTF-16 представляет собой кодировку с переменной шириной, в которой символы могут состоять из 1 или 2 16-битных кодовых точек (и s / 16/8 / g для UTF-8). – underscore_d 21 May 2017 в 14:42
Другие вопросы по тегам:

Похожие вопросы: