如何将wstring转换为string?


204

问题是如何将wstring转换为string?

我有下一个例子:

#include <string>
#include <iostream>

int main()
{
    std::wstring ws = L"Hello";
    std::string s( ws.begin(), ws.end() );

  //std::cout <<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;
    std::cout <<"std::string =     "<<s<<std::endl;
}

带有注释行的输出是:

std::string =     Hello
std::wstring =    Hello
std::string =     Hello

但不只是:

std::wstring =    Hello

示例中有什么问题吗?我可以进行上述转换吗?

编辑

新的示例(考虑了一些答案)是

#include <string>
#include <iostream>
#include <sstream>
#include <locale>

int main()
{
    setlocale(LC_CTYPE, "");

    const std::wstring ws = L"Hello";
    const std::string s( ws.begin(), ws.end() );

    std::cout<<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;

    std::stringstream ss;
    ss << ws.c_str();
    std::cout<<"std::stringstream =     "<<ss.str()<<std::endl;
}

输出为:

std::string =     Hello
std::wstring =    Hello
std::stringstream =     0x860283c

因此stringstream不能用于将wstring转换为string。


4
您如何在不指定编码的情况下问这个问题?
David Heffernan

5
@tenfour:为何要使用std::wstringstackoverflow.com/questions/1049947/…–
dalle,

11
@dalle如果您已经用UTF-16编码过的数据,那么UTF-16是否被认为有害就有些争议了。而且,就其价值而言,我认为任何转换形式都不有害。有害的是人们以为实际上他们不了解Unicode。
David Heffernan

2
它一定是跨平台的解决方案吗?
ali_bahoo 2011年

2
@dalle c ++标准未以任何方式提及utf(utf-8或utf-16)。找到一个链接,说明为什么utf-16无法用wstring编码?
2011年

Answers:


31

这是根据其他建议制定的解决方案:

#include <string>
#include <iostream>
#include <clocale>
#include <locale>
#include <vector>

int main() {
  std::setlocale(LC_ALL, "");
  const std::wstring ws = L"ħëłlö";
  const std::locale locale("");
  typedef std::codecvt<wchar_t, char, std::mbstate_t> converter_type;
  const converter_type& converter = std::use_facet<converter_type>(locale);
  std::vector<char> to(ws.length() * converter.max_length());
  std::mbstate_t state;
  const wchar_t* from_next;
  char* to_next;
  const converter_type::result result = converter.out(state, ws.data(), ws.data() + ws.length(), from_next, &to[0], &to[0] + to.size(), to_next);
  if (result == converter_type::ok or result == converter_type::noconv) {
    const std::string s(&to[0], to_next);
    std::cout <<"std::string =     "<<s<<std::endl;
  }
}

这通常适用于Linux,但会在Windows上产生问题。


@Phillip:代码的哪一部分取决于c语言环境?是std::setlocale(LC_ALL, "");真正需要的?
smerlin 2011年

2
使用也std::wcout.imbue(locale)应该做的工作,它的好处是它不会更改任何全局状态。
smerlin 2011年

32
std::wstring_convert来自C ++ 11 的from封装了很多此类噪声。
Cubbi 2011年

7
@Philipp,您的意思是“将在Windows上产生问题”?什么样的问题?
吉利

1
上面的代码给出了(如复制的)给我一个*** glibc detected *** test: malloc(): smallbin double linked list corrupted: 0x000000000180ea30 ***Linux 64位(gcc 4.7.3)。有人遇到这个吗?
hogliux

312

正如Cubbi在评论中指出的那样,std::wstring_convert(C ++ 11)提供了一个简洁的解决方案(您需要#include <locale><codecvt>):

std::wstring string_to_convert;

//setup converter
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;

//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str = converter.to_bytes( string_to_convert );

wcstombs在遇到此问题之前,我一直在使用繁琐的内存分配/解除分配组合。

http://en.cppreference.com/w/cpp/locale/wstring_convert

更新(2013.11.28)

一个班轮可以这样说(谢谢古斯先生的评论):

std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some string");

包装函数可以这样表示:(谢谢ArmanSchwarz的评论)

std::wstring s2ws(const std::string& str)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.from_bytes(str);
}

std::string ws2s(const std::wstring& wstr)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.to_bytes(wstr);
}

注意:是否将string/ wstring作为引用或文字传递给函数存在争议(由于C ++ 11和编译器更新)。我将把决定权留给实施人员,但这是值得知道的。

注意:我std::codecvt_utf8在上面的代码中使用,但是如果您不使用UTF-8,则需要将其更改为您正在使用的适当编码:

http://en.cppreference.com/w/cpp/header/codecvt


25
请+1:这是进行字符串转换的官方C ++标准方法。您也可以使用from_bytes进行另一种转换。因为我个人喜欢单线,所以这里是我的版本:std::wstring str = std::wstring_convert<std::codecvt_utf<wchar_t>>().from_bytes("some string");
Guss 2013年

7
从g ++ 4.8.2开始,似乎en.cppreference.com/w/cpp/header/codecvt不再可用。目前,两个s2ws和ws2s方法在linux下不起作用
Begui 2014年

5
似乎已弃用(stackoverflow.com/a/42946556/211176)。当我尝试运行此代码时,我的编译器引发错误
adam_0


5
对于任何担心C ++ 17和进一步兼容性(由于弃用)的人,请参阅:stackoverflow.com/a/18597384/6205379
Timo

128

解决方案来自:http : //forums.devshed.com/c-programming-42/wstring-to-string-444006.html

std::wstring wide( L"Wide" ); 
std::string str( wide.begin(), wide.end() );

// Will print no problemo!
std::cout << str << std::endl;

请注意,这里根本没有进行字符集转换。这样做是简单地分配给每个迭代wchar_tchar-一截断转换。它使用std :: string c'tor

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

如评论所述:

值0-127在几乎所有编码中都是相同的,因此截短所有小于127的值会得到相同的文本。插入中文字符,您会看到失败的消息。

--

Windows代码页1252(Windows英语默认值)的值128-255和unicode的值128-255基本相同,因此,如果这是代码页,则您使用的大多数这些字符都应截断为正确的值。(我完全希望á和õ能够正常工作,我知道我们的代码在é上依赖于此,我将很快对其进行修复)

并注意范围内的代码点0x80 - 0x9FWin1252无法正常工作。这包括œžŸ,...


2
奇怪的是,这在Visual Studio 10上有效。发生了什么?对于原始字符串的所有元素,这将导致从wchar_t到char的截断分配。
PedroLamarão13年

6
...涉及任何非拉丁字符时
JavaRunner

8
@PedroLamarão:几乎每种编码中的值0-127都是相同的,因此截断所有小于127的值会得到相同的文本。插入中文字符,您将看到失败。
Mooing Duck 2013年

3
@PedroLamarão:值窗口128-255代码页1252(Windows的默认英语)和值的Unicode的128-255 大多是相同的,所以如果这是你正在使用德代码页大部分的字符将会被截断到正确的价值观。(我完全期望á和õ能够正常工作,我知道我们的工作代码依赖于é,我很快会解决)
Mooing Duck 2013年

2
这很好。MSVS 2015和MSVS 2017以及MINGW / g ++和clang ++。合法++ 1。
Nikos

11

不用包括语言环境和所有其他花哨的东西,如果您知道FACT,那么您的字符串是可转换的,只需执行以下操作:

#include <iostream>
#include <string>

using namespace std;

int main()
{
  wstring w(L"bla");
  string result;
  for(char x : w)
    result += x;

  cout << result << '\n';
}

这里的例子


2
+1,因为它是适用于某些情况的简单解决方案(对于“ works”的松散定义,我可能会添加)。
乌鸦

2
几乎与namar0x0309的解决方案相同,这是更优雅的恕我直言。但这就是我。
onitake 2013年

我简化了您的代码,使其实际上只需进行最小的修改即可;-)
rubenvb

9
-1如果您有wstring,则可能是您正在处理多字节字符。如果您知道该字符串是微不足道的可转换的,那么您就不会首先处理wstring了。更可能的是,您正在处理另一个希望正确处理wstring的库。截断wchars只是乞求以后很难跟踪bug。另外,您应该使用“字符串结果(w.begin(),w.end());” 如果要执行此操作,请避免可能触发许多重新分配的循环。
肯(Kian)

7

我相信官方的方式仍然是多方面的codecvt(您需要某种语言环境感知的翻译),例如

resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
  in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);

或类似的东西,我周围没有工作代码。但是我不确定这些天有多少人在使用这种机器,有多少人只是简单地请求指向内存的指针,然后让ICU或其他一些库处理这些细节。


7

该代码有两个问题:

  1. const std::string s( ws.begin(), ws.end() );不需要进行转换即可将宽字符正确映射到窄字符。每个宽字符最有可能会被投射到char
    这个问题的解决方案已经在kem的答案中给出,并且涉及narrow语言环境ctype方面的功能。

  2. 你正在写输出都std::coutstd::wcout在同一个程序。二者coutwcout用相同的流(相关联stdout),并且使用既作为面向字节的流(作为相同流的结果cout一样)和宽面向流(如wcout不)没有被定义。
    最好的选择是避免将窄输出和宽输出混合到同一(基础)流中。对于stdout/ cout/ wcout,您可以尝试stdout在宽输出和窄输出之间切换时切换方向(反之亦然):

    #include <iostream>
    #include <stdio.h>
    #include <wchar.h>
    
    int main() {
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
        fwide(stdout, -1); // switch to narrow
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
    }

是的,这可以解决使用cout和wcout的问题。
2011年

7

默认编码为:

  • Windows UTF-16。
  • Linux UTF-8。
  • MacOS UTF-8。

这段代码有两种形式,可以将std :: string转换为std :: wstring,将std :: wstring转换为std :: string。如果否定#if定义WIN32,则会得到相同的结果。

1. std :: string到std :: wstring

MultiByteToWideChar WinAPI

_mbstowcs_s_l

#if defined WIN32
#include <windows.h>
#endif

std::wstring StringToWideString(std::string str)
{
    if (str.empty())
    {
        return std::wstring();
    }
    size_t len = str.length() + 1;
    std::wstring ret = std::wstring(len, 0);
#if defined WIN32
    int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &str[0], str.size(), &ret[0], len);
    ret.resize(size);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t retval = _mbstowcs_s_l(&size, &ret[0], len, &str[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

2.将std :: wstring转换为std :: string

WideCharToMultiByte WinAPI

_wcstombs_s_l

std::string WidestringToString(std::wstring wstr)
{
    if (wstr.empty())
    {
        return std::string();
    }
#if defined WIN32
    int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), NULL, 0, NULL, NULL);
    std::string ret = std::string(size, 0);
    WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), &ret[0], size, NULL, NULL);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t err = _wcstombs_s_l(&size, NULL, 0, &wstr[0], _TRUNCATE, lc);
    std::string ret = std::string(size, 0);
    err = _wcstombs_s_l(&size, &ret[0], size, &wstr[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

3.在Windows上,您需要使用WinAPI打印unicode。

WriteConsole

#if defined _WIN32
    void WriteLineUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
    }

    void WriteLineUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
    }

4.在主程序上。

#if defined _WIN32
int wmain(int argc, WCHAR ** args)
#else
int main(int argc, CHAR ** args)
#endif
{
    std::string source = u8"ÜüΩωЙ你月曜日\na🐕èéøÞǽлљΣæča🐕🐕";
    std::wstring wsource = L"ÜüΩωЙ你月曜日\na🐕èéøÞǽлљΣæča🐕🐕";

    WriteLineUnicode(L"@" + StringToWideString(source) + L"@");
    WriteLineUnicode("@" + WidestringToString(wsource) + "@");
    return EXIT_SUCCESS;
}

5.最后,您需要在控制台中对Unicode字符提供强大而完整的支持。 我建议使用ConEmu并将其设置为Windows上的默认终端。您需要将Visual Studio挂接到ConEmu。请记住,Visual Studio的exe文件是devenv.exe

在带有VC ++的Visual Studio 2017上测试; std = c ++ 17。

结果

结果1


6

您也可以直接使用ctype facet的缩小方法:

#include <clocale>
#include <语言环境>
#include <string>
#include <vector>

内联std :: string窄(std :: wstring const&text)
{
    std :: locale const loc(“”);
    wchar_t const * from = text.c_str();
    std :: size_t const len = text.size();
    std :: vector <char>缓冲区(len +1);
    std :: use_facet <std :: ctype <wchar_t>>(loc).narrow(from,from + len,'_',&buffer [0]);
    返回std :: string(&buffer [0],&buffer [len]);
}

6

在撰写此答案时,排名第一的Google搜索“转换字符串wstring”将使您进入此页面。我的答案显示了如何将字符串转换为wstring,尽管这不是实际问题,我可能应该删除此答案,但这被认为是错误的形式。 您可能想跳到该StackOverflow答案,该答案现在比该页面的排名更高。


这是将字符串,wstring和混合字符串常量组合到wstring的一种方法。使用wstringstream类。

#include <sstream>

std::string narrow = "narrow";
std::wstring wide = "wide";

std::wstringstream cls;
cls << " abc " << narrow.c_str() << L" def " << wide.c_str();
std::wstring total= cls.str();

13
这不是wstring到字符串的转换
poitroae 2012年

1
@Michael您能解释一下吗?那这不正确吗?没有更多详细信息,您的评论将无济于事。
Nate 2012年

1
这是一个字符串到wstring的转换。即与问题相反。
杰夫·麦金托克

4

除了转换类型之外,您还应该注意字符串的实际格式。

在为多字节字符集进行编译时,Visual Studio和Win API假定使用UTF8(实际上是Windows编码,它是Windows-28591)。
在为Unicode字符集进行编译时,Visual Studio和Win API均采用UTF16。

因此,您还必须将字符串也从UTF16转换为UTF8格式,而不仅仅是转换为std :: string。
当使用诸如非拉丁语言的多字符格式时,这将变得必要。

想法是确定std::wstring 始终代表UTF16
std::string 始终代表UTF8

这不是由编译器强制执行的,而是具有更好的策略。请注意,我用于定义UTF16(L)和UTF8(u8)的字符串前缀。

要在两种类型之间进行转换,应使用:std :: codecvt_utf8_utf16 <wchar_t>

#include <string>

#include <codecvt>

int main()
{

    std::string original8 = u8"הלו";

    std::wstring original16 = L"הלו";

    //C++11 format converter
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    //convert to UTF8 and std::string
    std::string utf8NativeString = convert.to_bytes(original16);

    std::wstring utf16NativeString = convert.from_bytes(original8);

    assert(utf8NativeString == original8);
    assert(utf16NativeString == original16);

    return 0;
}

3

就我而言,我必须使用多字节字符(MBCS),并且我想使用std :: string和std :: wstring。并且不能使用c ++ 11。因此,我使用mbstowcs和wcstombs。

我通过使用new,delete []来实现相同的功能,但是比这慢。

这可以帮助如何:在各种字符串类型之间进行转换

编辑

但是,如果转换为wstring且源字符串不是字母和多字节字符串,则无法正常工作。因此,我将wcstombs更改为WideCharToMultiByte。

#include <string>

std::wstring get_wstr_from_sz(const char* psz)
{
    //I think it's enough to my case
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    size_t len = strlen(psz) + 1;

    if (len >= sizeof(buf) / sizeof(wchar_t))
    {
        pbuf = L"error";
    }
    else
    {
        size_t converted;
        mbstowcs_s(&converted, buf, psz, _TRUNCATE);
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wsz(const wchar_t* pwsz)
{
    char buf[0x400];
    char *pbuf = buf;
    size_t len = wcslen(pwsz)*2 + 1;

    if (len >= sizeof(buf))
    {
        pbuf = "error";
    }
    else
    {
        size_t converted;
        wcstombs_s(&converted, buf, pwsz, _TRUNCATE);
    }

    return std::string(pbuf);
}

编辑以使用“ MultiByteToWideChar”而不是“ wcstombs”

#include <Windows.h>
#include <boost/shared_ptr.hpp>
#include "string_util.h"

std::wstring get_wstring_from_sz(const char* psz)
{
    int res;
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    boost::shared_ptr<wchar_t[]> shared_pbuf;

    res = MultiByteToWideChar(CP_ACP, 0, psz, -1, buf, sizeof(buf)/sizeof(wchar_t));

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);

        shared_pbuf = boost::shared_ptr<wchar_t[]>(new wchar_t[res]);

        pbuf = shared_pbuf.get();

        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, pbuf, res);
    }
    else if (0 == res)
    {
        pbuf = L"error";
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wcs(const wchar_t* pcs)
{
    int res;
    char buf[0x400];
    char* pbuf = buf;
    boost::shared_ptr<char[]> shared_pbuf;

    res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, buf, sizeof(buf), NULL, NULL);

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, NULL, 0, NULL, NULL);

        shared_pbuf = boost::shared_ptr<char[]>(new char[res]);

        pbuf = shared_pbuf.get();

        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, pbuf, res, NULL, NULL);
    }
    else if (0 == res)
    {
        pbuf = "error";
    }

    return std::string(pbuf);
}

如何在gcc 4.8中使用“ wcstombs_s”?因为我看到这是C ++ 11功能。
cristian

@cristian您可以使用此功能的“不安全”版本wcstombs()
Vizor

3

此解决方案的灵感来自dk123的解决方案,但使用的语言环境依赖于编解码器构面。结果是使用区域设置编码的字符串而不是UTF-8(如果未将其设置为区域设置):

std::string w2s(const std::wstring &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}

std::wstring s2w(const std::string &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}

我一直在寻找它,但找不到。最终,我发现可以通过std::locale使用std::use_facet()具有正确类型名的函数来获得正确的方面。希望这可以帮助。


Vizor,使用与语言环境相关的方面进行转换的优点(如果有)是什么?
Marc.2377'9

如果您使用系统中的字符串,例如通过控制台输入。
Vizor

1

万一其他人感兴趣:我需要一个可以在a stringwstring期望的位置互换使用的类。下面的类convertible_string,基于dk123的溶液,可与一个被初始化stringchar const*wstringwchar_t const*,并且可以通过被分配给或隐式转换到任何一个stringwstring(因此可以被传递到该采取任一功能)。

class convertible_string
{
public:
    // default ctor
    convertible_string()
    {}

    /* conversion ctors */
    convertible_string(std::string const& value) : value_(value)
    {}
    convertible_string(char const* val_array) : value_(val_array)
    {}
    convertible_string(std::wstring const& wvalue) : value_(ws2s(wvalue))
    {}
    convertible_string(wchar_t const* wval_array) : value_(ws2s(std::wstring(wval_array)))
    {}

    /* assignment operators */
    convertible_string& operator=(std::string const& value)
    {
        value_ = value;
        return *this;
    }
    convertible_string& operator=(std::wstring const& wvalue)
    {
        value_ = ws2s(wvalue);
        return *this;
    }

    /* implicit conversion operators */
    operator std::string() const { return value_; }
    operator std::wstring() const { return s2ws(value_); }
private:
    std::string value_;
};

1
我宁愿将此类存储std::wstring在类中,而不是存储std::stringstd::wstring在需要时进行转换以获取std::wstring。因为它std::wstring比更快,std::string并且兼容性更好。即使它消耗的内存也比std::string
0xAA55

0
#include <boost/locale.hpp>
namespace lcv = boost::locale::conv;

inline std::wstring fromUTF8(const std::string& s)
{ return lcv::utf_to_utf<wchar_t>(s); }

inline std::string toUTF8(const std::wstring& ws)
{ return lcv::utf_to_utf<char>(ws); }

-1

我在下面使用将wstring转换为string。

std::string strTo;
char *szTo = new char[someParam.length() + 1];
szTo[someParam.size()] = '\0';
WideCharToMultiByte(CP_ACP, 0, someParam.c_str(), -1, szTo, (int)someParam.length(), NULL, NULL);
strTo = szTo;
delete szTo;

你似乎缺少一个标准的头(<string>)和一个定义WideCharToMultiByte()-是一些包装器std::wctomb()
Toby Speight '18

-3
// Embarcadero C++ Builder 

// convertion string to wstring
string str1 = "hello";
String str2 = str1;         // typedef UnicodeString String;   -> str2 contains now u"hello";

// convertion wstring to string
String str2 = u"hello";
string str1 = UTF8string(str2).c_str();   // -> str1 contains now "hello"

3
请在回答中解释您在做什么,否则可能会被删除
CodeFanatic 2014年

1
UTF8string函数从何而来?
Jean-Christophe Blanchard
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.