在 Unix 环境中正确设置 NLS_LANG (文档 ID 1548858.1)
适用于:
Oracle Database Cloud Schema Service - 版本 N/A 和更高版本
Oracle Database Exadata Express Cloud Service - 版本 N/A 和更高版本
Oracle Database Exadata Cloud Machine - 版本 N/A 和更高版本
Oracle Cloud Infrastructure - Database Service - 版本 N/A 和更高版本
Oracle Database Backup Service - 版本 N/A 和更高版本
本文档所含信息适用于所有平台
目标
说明如何在 Unix 环境中正确设置 NLS_LANG。
解决方案
请注意Server使用的LANG和NLS_LANG变量并不会影响通过Listener连接进来的客户端。
要调试显示问题(当您看到奇怪的符号或字符,如 "?" , "¿" or "ÃÂÃÂÂ"),请首先使用 Oracle SQL Developer 进行调试。
Oracle SQL Developer 是一款无需在客户端进行 Oracle NLS 配置的“已知的可用客户端”。
检查配置 Oracle SQL Developer 的文档及截屏请参见note 1628060.1 How to diagnose losing characters , getting "funny" output when inserting or selecting other than A-Z,a-z data ( = non English data like Chinese, Russian, Hebrew , insert any language here to the list that is not English) CHAR, VARCHAR2, LONG or CLOB
1- 检查 locale 的设置,如果需要,请更正。
此处所用示例是配置 Unix 环境以便能够在 Unix 计算机的 shell 中使用 Unicode (UTF-8)、配置 Telnet/SSH 软件、以及将 NLS_LANG 设置为 UTF8 / AL32UTF8 以用于 sqlplus。有关在数据库级别使用 Unicode 的更多信息,请参阅 Note:788156.1 AL32UTF8 / UTF8 (Unicode) Database Character Set Implications
要查看当前设置,请使用 “locale” 命令,如下所示:
$ locale
输出示例:
LANG=fr_FR
LC_CTYPE="fr_FR.iso885915@euro"
LC_COLLATE="fr_FR.iso885915@euro"
LC_MONETARY="fr_FR.iso885915@euro"
LC_NUMERIC="fr_FR.iso885915@euro"
LC_TIME="fr_FR.iso885915@euro"
LC_MESSAGES="fr_FR.iso885915@euro"
LC_ALL=fr_FR.iso885915@euro
大多数 Unix 版本默认设置为:
$ locale
LANG=
LC_CTYPE="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_MESSAGES="C"
LC_ALL=
“C”是指 US7ASCII,这意味着仅可显示 a-z、A-Z 和 0-9。
我们建议尽可能使用 UTF-8,如下所示:
$ locale
LANG=en_US
LC_CTYPE="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_ALL=en_US.UTF-8
如果您已经选择了一个值,例如在 Linux 上使用 “en_US.UTF-8”,可进行如下设置:
$ export LC_ALL=en_US.UTF-8
或
% setenv LC_ALL en_US.UTF-8
请注意,此命令的输出/语法在不同 Unix 环境中并不完全相同。如果您对如何在特定 Unix/Linux 版本中配置用户环境有任何问题,请咨询您的 OS 供应商。
2- 检查所选择的 locale 是否确实已安装,如果需要,请安装。
要查看所有安装的 locale,请执行以下语句:
$ locale -a
示例输出:
$ locale -a
POSIX
common
en_US.UTF-8
C
iso_8859_1
iso_8859_15
en_CA
en_CA.ISO8859-1
en_US
en_US.ISO8859-1
en_US.ISO8859-15
en_US.ISO8859-15@euro
fr_CA
fr_CA.ISO8859-1
th
th_TH
th_TH.TIS620
ja
...
这将列出 Unix 计算机上所有已安装的 locale。
例如,如果您想要使用 “fr_FR.iso885915@euro”,但它不在列表中,则您需要先安装它。
如果您将用户环境设置为未安装的 locale,您不会收到错误消息,但该设置可能不起作用。
请注意,您需要安装完全匹配的 locale,如果您安装了 “fr_FR.UTF-8”或“UTF-8”,但想要使用 “en_US.UTF-8”,则需要安装 “en_US.UTF-8”。
Locale 参数语法为 “language(_territory)(.encoding)(@modifier)”。language(_territory) 部分用于确定日期的默认格式、OS 级别的接口语言等(有关更多信息,请参阅系统文档),因此,这部分的设置需要您来决定,而不是 Oracle;但是,如果您希望使用 Unicode shell 环境,则最后的 (.encoding) 部分需要为 UTF-8。注意 Unix Locale 的 Language 和 Territory 设置与在 shell 中使用字符 的能力无关。Locale 设置为 ja_JA.ISO8859-1不代表您可以使用日文,因为 ISO8859-1 不识别日文字符。但 Locale 设置为 en_US.UTF-8 将允许在 shell 中使用日文(假定您的 telnet/ssh 客户端设置正确)。
在上边的示例中,“en_US.UTF-8” 存在于列表中,因此我们可以在此服务器上使用该设置。
3- 检查 telnet/ssh 软件是否已正确配置。
您需要检查 telnet/ssh 软件是否已正确配置。telnet/ssh 软件负责将 Unix locale 转换给客户端环境(多半为 Windows 系统)。
我们建议首先使用免费的 PUTTY 客户端进行尝试,据我们所知,它是与 Unicode 最佳兼容的一款客户端工具。您可从此站点下载 Putty:http://www.chiark.greenend.org.uk/~sgtatham/putty/
如示例中一样,在 Unix 端使用 “en_US.UTF-8”,则在 Putty 中更改如下设置:
打开配置窗口,导航到“Window(窗口)”、“Translation(转换)”,并将“Received data assumed to be in which character set(假定接收到的数据使用此字符集)”设置为“UTF-8”。这需要与 Unix shell 端的编码匹配。如果locale不是UTF-8, 但是比如是en_US.ISO8859-1那么选择"ISO-8859-1:1998 (Latin-1, West Europe)"
导航到“Window(窗口)”、“Appearance(外观)”,然后在“Font used in the terminal window(终端窗口中使用的字体)”中选择一种字体,以便支持您想要使用/查看的语言。
请注意,编码/字符集与字体之间的根本区别在于,编码/字符集定义了每种编码包括哪些字符,而字体用于 OS 在屏幕上“绘制”由编码定义的字符。使用 Telnet/ssh 等基于文本的仿真程序,远程端不会向客户端发送/从客户端接收“字符”,而使用特定字符集进行编码,客户端 OS 使用 Telnet/ssh 客户端的字体在屏幕上绘制这些字符。这意味着在使用任何字体之前,客户端和远程端首先需要就使用的编码达成一致。
在 Windows 客户端,大多数非亚洲语言可以使用默认的“Courier New” Windows 字体,“Arial Unicode MS”为更加完整的字体。“Arial Unicode MS”通常在所有安装了 Office 2002 或更高版本的 Windows 客户端均可用,可支持各式各样的字符。要了解此字体支持哪些语言,请参阅 http://support.microsoft.com/kb/q287247/ 。如果未安装 office 2002,则可以尝试 GNU FreeFont http://www.gnu.org/software/freefont/index.html 集合。另一个关于 Unicode 字体的非常优秀的资源是 Alan Wood's website。例如,Shareware“Code2000”字体是最完整的“通用”字体之一。
在 Windows 上,Windows 工具“字符映射表”可用于查看字体中包含哪些字符,或者您可以在编辑器中(如 Wordpad)输入字符并选择字体,然后看这些字符是否正确显示。
请务必检查 telnet/ssh 客户端配置,几乎在所有情况下,在“Unix 提示符”中显示字符存在问题的原因都是由于 telnet/ssh 客户端配置不正确导致,或者是正在使用不可配置的 telnet/ssh 客户端而导致,如标准 Windows telnet。
如果使用 Putty 可以正确显示,但使用您的 telnet/ssh 软件包却不可正确显示,请咨询您的 telnet/ssh 软件供应商。
如果您不使用 telnet/ssh 客户端而使用“真正的”Unix 显示器,请参阅 Note 265090.1 How to check Unix terminal Environments for the capability to display extended characters.
4- 设置 NLS_LANG 并测试。
当您执行完下列操作后:
1) 正确配置 LC_ALL
2) 确认所使用的 locale 已安装
3) 配置好 telnet/ssh 客户端
然后您就可以使用 NLS_LANG 匹配 locale。
NLS_LANG 的构成为:NLS_LANG=<NLS_LANGUAGE>_<NLS_TERRITORY>.<clients characterset>
以 locale “en_US.UTF-8”为例,这意味着应该将 NLS_LANG 设置为 =AMERICAN_AMERICA.AL32UTF8;如果 locale 设置为“en_US.UTF-8”,则相应的 NLS_LANG 设置将为 AMERICAN_AMERICA.AL32UTF8。
请注意:
* UTF-8 (Unix) 和 UTF8/AL32UTF8 (Oracle) 的表示法之间的区别
* NLS_LANG 的 NLS_LANGUAGE 和 NLS_TERRITORY 设置 与在客户端上“查看”字符/在数据库中存储字符的能力无关。 NLS_LANG 设置为 JAPANESE_JAPAN.WE8ISO8859P15 将不允许存储日文,因为 WE8ISO8859P15 不识别日文字符。但 NLS_LANG 设置为 AMERICAN_AMERICA.UTF8 将允许使用/存储日文(假定您的 telnet/ssh 客户端和 Locale 设置正确,且您的数据库可以存储日文 - 例如使用 UTF8 或 AL32UTF8 NLS_CHARACTERSET 的数据库)
* 要使 NLS_LANGUAGE 和 NLS_TERRITORY 匹配 LC_ALL 中的 language(_territory) 值,请在 database globalizaton support guide appendix A. 中查看相应的 Oracle 语言和地区值。
因此,以 Unix 用户身份登录并执行以下操作:
a) 对照 locale 检查 LC_ALL 是否设置正确(假定此处为 en_US.UTF-8)
b) 仔细检查 Telnet/ssh 客户端配置(假定此处 Putty 按第 3 点所述进行配置)
c) 设置 NLS_LANG 以匹配 locale 设置
$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
或
% setenv NLS_LANG AMERICAN_AMERICA.AL32UTF8
之后通过下边的小窍门检查 sqlplus 侦测到的 NLS_LANG 设置:
$ sqlplus /nolog
SQL>@.[$NLS_LANG].
如果您得到下边的结果:
SQL>@.[$NLS_LANG].
SP2-0310: unable to open file ".[AMERICAN_AMERICA.AL32UTF8]..sql"
'[]'中包含的"文件名"就是 sqlplus 将会使用的 NLS_LANG 设置。
如果您得到下边的结果:
SQL>@.[$NLS_LANG].
SP2-0310: unable to open file ".[$NLS_LANG]..sql"
那么表示 NLS_LANG 没有设或者 sqlplus 没有侦测到。
如果您得到" SP2-0310: unable to open file ".[$NLS_LANG]..sql" " 但是下边的命令能返回 AMERICAN_AMERICA.AL32UTF8:
SQL>HOST ECHO $NLS_LANG
那么表明 NLS_LANG 设置了但是没有在环境中 *export*
d) 使用 sqlplus 连接到数据库并查询一些数据。
一个很好的检查方法是执行以下语句“select UNISTR('\20AC') from dual;”。如果您选择使用9i 或更高版本数据库,和一个正确的 UTF-8 或 ISO8859-15 Unix 环境,则一个欧元符号会被正确的显示出来,因为这样的环境可以正确处理欧洲语言(AL32UTF8、WE8MSWIN1252、...)。如果可以显示欧元符号但数据库中存储的数据未正确显示,则表明客户端已正确配置,但数据库中的现有数据现在/过去未正确存储。您将需要更正数据库中的现有数据,直至其可在正确配置的客户端显示 Note:225938.1 Database Character Set Healthcheck.
如果此方法有效,则将用户配置文件中的 NLS_LANG 也设置为这个值以用于 sqlplus。
如果已完成,则您已针对在 sqlplus 中交互式插入和查询数据进行了正确配置。
但是,这并不意味着此设置可用于所有应用程序。
NLS_LANG 用于让 Oracle 客户端知道哪些编码/字符集数据将传输到客户端库。如果您在此 Unix 计算机上运行 Web 应用程序且输出 iso-8859-1 数据,则对于该应用程序,正确的 NLS_LANG 为 WE8ISO8859P1(即使 Unix locale 为 UTF-8)
Note 229786.1 NLS_LANG and webservers explained.
Note 115001.1 NLS_LANG Client Settings and JDBC Drivers
5- 如果上述方法都不起作用怎么办?
如果您未看见预期的字符,则请再次检查您的设置。剩余的最常见问题是您的 Telnet/ssh 仿真程序未正确配置。
然而,也可能是您的数据库中数据不正确。
一个简单的检查方法是:
使用 Windows 客户端,从以下地址下载并安装 SqlDeveloper http://www.oracle.com/technology/products/database/sql_developer/index.html ,连接到您的数据库并查看数据在该工具中是否正确显示。
如果数据可以在 SqlDeveloper 中显示,则数据库中的数据是正确的,问题在于客户端。
如果数据未在 SqlDeveloper 中显示,则表明数据库中的数据不正确,这意味着即使您的客户端已正确配置,数据也无法正确显示。
较难的检查方法是:
如果您使用 select 语句,例如“select ename from scott.emp where empno='7369';”来返回一行数据,则执行以下语句“select dump(ename,1016),ename from scott.emp where empno='7369';”。
您可以在以下文档中查看代码是否匹配您期望数据库字符集中的字符 ( select value from NLS_DATABASE_PARAMETERS where parameter='NLS_CHARACTERSET'; ) Note 282336.1 Charts of most current mono-byte Character sets,或者如果您使用的是 (AL32)UTF8 数据库,请使用 Note 69518.1 Storing and Checking Character Codepoints in a UTF8/AL32UTF8 (Unicode) database
如果您不知道问题是什么原因造成的,请新开一个服务请求,参阅以下文档并提供所需信息:
* Note 226692.1 Finding out your NLS Setup 文档中要求的信息。
* 在您的环境中执行这个select语句“select dump(ename,1016),ename from scott.emp where empno='7369';”并用 spool 保存结果到文件。(!请勿直接复制粘贴!)
6- 进行更深入的调试。
第 1-4 步应足以解决 99% 的问题,本文档的剩余部分将讨论深入调试
在某些平台上,使用下列语法可以有效地获取关于
实际使用的代码页的更多详细信息:
$ locale LC_CTYPE | head
HP-UX 环境中的输出示例:
""
""
"iso885915"
""
Linux 环境中的输出示例:
upper;lower;alpha;digit;xdigit;space;print;graph;blank;cntrl;punct;alnum;combining;combining_level3
toupper;tolower;totitle
16
1
ISO-8859-15
70
84
1
0
1
$ locale LC_CTYPE | head
upper;lower;alpha;digit;xdigit;space;print;graph;blank;cntrl;punct;alnum;combining;combining_level3
toupper;tolower;totitle
16
6
UTF-8
70
84
1
0
1
在 Solaris、AIX、TRU64 上,此语法不能提供相关的补充信息。
要查找关于这些设置的更多详细信息:
在 Solaris 上,请查看 /usr/lib/locale。
在 AIX 上,请查看 /usr/lib/nls/README
在 TRU64 上,请查看 /usr/lib/nls
在 HP-UX 上,请查看 /usr/lib/nls/config
在 Linux 上,请查看 /usr/share/locale/locale.alias
如何检查操作系统管理的字符编码:
要了解 Unix 环境中针对字符所生成的字符编码,
可以按如下所示使用“od”命令(使用 iso-8859-1 locale 的示例):
$ od -xc
é
0000000 00e9
351 \0
0000001
正如您所见,hexa-decimal 编码 e9 对应于“é”(小写 e 重读音节)
351 是对应的八进制值(八进制为 od 命令的固有状态)。
您还可以使用“echo”命令检查对应于字符编码的字符,如下所示:
对于 Solaris、AIX、HP-UX、TRU64:
$echo '\0351'
é
对于 Linux:
$echo -e '\0351'
é
正如您所见,echo 使用八进制值,因此您需要将要检查的值转换为八进制。
7- Locale 和 NLS_LANG 是否*需要*与数据库字符集匹配?
不需要,Locale 和 NLS_LANG 设置(如果适用,还包括 telnet/ssh config)需要互相匹配,但从技术角度看它们均与数据库字符集无关,并且它们仅针对该客户端环境相关。
假定您使用 AL32UTF8 NLS_CHARACTERSET 数据库。如果将 Unix 环境配置为(例如)fr_FR.iso885915@euro(相匹配的 NLS_LANG 为 FRENCH_FRANCE.WE8ISO8859P15),则您可以在 Unix shell 中查看/插入欧元字符和法文或西班牙文,但无法查看/插入俄文或中文(也就是 iso885915 中未定义的任何语言)。
然而,如果您使用可以存储/处理这些语言的远程客户端(例如使用 Sqldeveloper 的 Windows 客户端),则可以向 AL32UTF8 数据库插入这些语言或从该数据库选择这些语言。原因很简单,因为服务器 NLS_LANG/Locale 设置仅在服务器本身作为客户端的情况下有关。
许多客户都遇到过这样的麻烦,由于将数据库 NLS_CHARACTERSET 更改为 (AL32)UTF8 从而需要“更正”Unix shell,其实只要不将 Unix 服务器本身作为客户端用于数据输入,则可以免去这些麻烦。您其实更应该担心的是最终用户实际插入数据的客户端。能够在服务器上使用 sqlplus 查看/插入中文可能是不错的体验,但即使奏效,这也与您的 Windows 客户端(例如)无关,因为 Windows 客户端设置与 Unix 端完全无关。对于 Windows 客户端,请参阅 Note 179133.1 The correct NLS_LANG in a Windows Environment
请注意,在服务器上加载普通文本文件时,sqlldr 的字符集取决于该文本/普通文件的字符集,而不是数据库字符集或所使用的 Unix locale,请参阅 Note 227330.1 Character Sets & Conversion - Frequently Asked Questions / point 18. What is the best way to load non-US7ASCII characters using SQL*Loader or External Tables?
8-对于NLS_CHARACTERSET是"xx8MSWIN12xx"(如WE8MSWIN1252等等)的数据库,最好的LANG 和 NLS_LANG的设置是什么
一个最常被问到的问题是:对于一个NLS_CHARACTERSET是"xx8MSWIN12xx"(如WE8MSWIN1252等等)的数据库,在Unix client上正确的LANG和NLS_LANG设置是什么?
Server上使用的LANG 和 NLS_LANG并不会影响通过Listener连接进来的客户端。.
很可能你是通过telnet/ssh连接上来做一些管理的工作,而不是真正的输入应用程序数据。.
在这种情况下,可以在Unix profile中把LANG设置为iso-8859-1,把NLS_LANG设置为AMERICAN_AMERICA.WE8MSWIN1252.
从技术上讲这并不是100%正确,但却是个好方案,因为你可以在sqlplus里很简单的运行"xx8MSWIN12xx"编码的脚本(比如在windows操作系统中创建的脚本),并且对于传统的exp/imp你不需要担心NLS_LANG的设置。.
注意:你很可能不能够在telnet环境里看到特殊字符,如欧元符号或者阿拉伯文。.
但是你在telnet环境中看不到特殊字符,并不影响通过listener连接进来的(Windows)客户端.
如果你想仔细检查数据,那么我们建议你使用SqlDevelper来检查;这个工具是一个非常好的客户端,它不需要任何NLS的设置。.
note 1628060.1 How to diagnose losing characters , getting "funny" output when inserting or selecting other than A-Z,a-z data ( = non English data like Chinese, Russian, Hebrew , insert any language here to the list that is not English) CHAR, VARCHAR2, LONG or CLOB
如果数据可以在SQLdeveloper中正确显示,那么我们就可以确认它在数据库中是正确的。.
如果你想在Unix中看到"xx8MSWIN12xx"的所有符号(比如欧元符号或者阿拉伯文或者...),那么我们建议你把LANG设置为UTF-8,并且把NLS_LANG设置为AMERICAN_AMERICA.UTF8
参考
NOTE:115001.1 - NLS_LANG Client Settings and JDBC Drivers
NOTE:158577.1 - NLS_LANG Explained (How does Client-Server Character Conversion Work?)
NOTE:227330.1 - Character Sets & Conversion - Frequently Asked Questions
NOTE:265090.1 - How to check Unix terminal Environments for the capability to display extended characters.
NOTE:229786.1 - NLS_LANG and webservers explained.
NOTE:179133.1 - The Correct NLS_LANG in a Microsoft Windows Environment