Shift_JISとCP932でマッピングが違う文字
違う文字一覧
1. —と―
2. 〜と~
3. ‖と∥
4. −と-
5. ¢と¢
6. £と£
7. ¬と¬
どう確認するか
code:dos
ver
code:py
python.exe
Type "help", "copyright", "credits" or "license" for more information.
なんか思てたんとちがう
それ以外は思った通りの文字が出た
code:python
>> b'\x81\x5c'.decode('shift_jis')
'―'
>> hex(ord(b'\x81\x5c'.decode('shift_jis')))
'0x2015'
>> '―'.encode('utf_8')
b'\xe2\x80\x95'
>> b'\x81\x5c'.decode('cp932')
'―'
>> hex(ord(b'\x81\x5c'.decode('cp932')))
'0x2015'
>> '―'.encode('utf_8')
b'\xe2\x80\x95'
code:python
>> '—'.encode('utf_8')
b'\xe2\x80\x94'
>> '—'.encode('shift_jis')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'shift_jis' codec can't encode character '\u2014' in position 0: illegal multibyte sequence
>> '—'.encode('cp932')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'cp932' codec can't encode character '\u2014' in position 0: illegal multibyte sequence
URLエンコード(UTF-8)%E2%80%94
URLエンコード(UTF-8)%E2%80%95
URLエンコード(EUC-JP)%A1%BD
URLエンコード(SHIFT_JIS)%81%5C
code:python
>> b'\x81\x60'.decode('shift_jis')
'〜'
>> hex(ord(b'\x81\x60'.decode('shift_jis')))
'0x301c'
>> '〜'.encode('utf_8')
b'\xe3\x80\x9c'
>> b'\x81\x60'.decode('cp932')
'~'
>> hex(ord(b'\x81\x60'.decode('cp932')))
'0xff5e'
>> '~'.encode('utf_8')
b'\xef\xbd\x9e'
WAVE DASH
URLエンコード(UTF-8)%E3%80%9C
URLエンコード(EUC-JP)%A1%C1
URLエンコード(SHIFT_JIS)%81%60
FULLWIDTH TILDE
URLエンコード(UTF-8)%EF%BD%9E
code:python
>> b'\x81\x61'.decode('shift_jis')
'‖'
>> hex(ord(b'\x81\x61'.decode('shift_jis')))
'0x2016'
>> '‖'.encode('utf_8')
b'\xe2\x80\x96'
>> b'\x81\x61'.decode('cp932')
'∥'
>> hex(ord(b'\x81\x61'.decode('cp932')))
'0x2225'
>> '∥'.encode('utf_8')
b'\xe2\x88\xa5'
URLエンコード(UTF-8)%E2%80%96
URLエンコード(EUC-JP)%A1%C2
URLエンコード(SHIFT_JIS)%81a
URLエンコード(UTF-8)%E2%88%A5
code:python
>> b'\x81\x7c'.decode('shift_jis')
'−'
>> hex(ord(b'\x81\x7c'.decode('shift_jis')))
'0x2212'
>> '−'.encode('utf_8')
b'\xe2\x88\x92'
>> b'\x81\x7c'.decode('cp932')
'-'
>> hex(ord(b'\x81\x7c'.decode('cp932')))
'0xff0d'
>> '-'.encode('utf_8')
b'\xef\xbc\x8d'
MINUS SIGN
URLエンコード(UTF-8)%E2%88%92
URLエンコード(EUC-JP)%A1%DD
URLエンコード(SHIFT_JIS)%81%7C
FULLWIDTH HYPHEN-MINUS
URLエンコード(UTF-8)%EF%BC%8D
code:python
>> b'\x81\x91'.decode('shift_jis')
'¢'
>> hex(ord(b'\x81\x91'.decode('shift_jis')))
'0xa2'
>> '¢'.encode('utf_8')
b'\xc2\xa2'
>> b'\x81\x91'.decode('cp932')
'¢'
>> hex(ord(b'\x81\x91'.decode('cp932')))
'0xffe0'
>> '¢'.encode('utf_8')
b'\xef\xbf\xa0'
CENT SIGN
URLエンコード(UTF-8)%C2%A2
URLエンコード(EUC-JP)%A1%F1
URLエンコード(SHIFT_JIS)%81%91
FULLWIDTH CENT SIGN
URLエンコード(UTF-8)%EF%BF%A0
code:python
>> b'\x81\x92'.decode('shift_jis')
'£'
>> hex(ord(b'\x81\x92'.decode('shift_jis')))
'0xa3'
>> '£'.encode('utf_8')
b'\xc2\xa3'
>> b'\x81\x92'.decode('cp932')
'£'
>> hex(ord(b'\x81\x92'.decode('cp932')))
'0xffe1'
>> '£'.encode('utf_8')
b'\xef\xbf\xa1'
POUND SIGN
URLエンコード(UTF-8)%C2%A3
URLエンコード(EUC-JP)%A1%F2
URLエンコード(SHIFT_JIS)%81%92
FULLWIDTH POUND SIGN
URLエンコード(UTF-8)%EF%BF%A1
code:python
>> b'\x81\xca'.decode('shift_jis')
'¬'
>> hex(ord(b'\x81\xca'.decode('shift_jis')))
'0xac'
>> '¬'.encode('utf_8')
b'\xc2\xac'
>> b'\x81\xca'.decode('cp932')
'¬'
>> hex(ord(b'\x81\xca'.decode('cp932')))
'0xffe2'
>> '¬'.encode('utf_8')
b'\xef\xbf\xa2'
NOT SIGN
URLエンコード(UTF-8)%C2%AC
URLエンコード(EUC-JP)%A2%CC
URLエンコード(SHIFT_JIS)%81%CA
FULLWIDTH NOT SIGN
URLエンコード(UTF-8)%EF%BF%A2
参考
table:quote
SJIS/MS932 SJISでデコード MS932でデコード
SJIS/MS932 →SJISでデコード →MS932でエンコード
0x815c U+2014 : EM DASH "—" 変換不能 0x8160 U+301c : WAVE DASH "〜" 変換不能 0x8161 U+2016 : DOUBLE VERTICAL LINE "‖" 変換不能 0x817c U+2212 : MINUS SIGN "−" 変換不能 0x8191 U+00a2 : CENT SIGN "¢" 0x8191 0x8192 U+00a3 : POUND SIGN "£" 0x8192 0x81ca U+00ac : NOT SIGN "¬" 0x81ca SJIS/MS932 →MS932でデコード →SJISでエンコード
SQL Serverで該当文字をinsertしてみた
code:sql
-- 一時テーブル作成
create table #t(vc varchar (4), nvc nvarchar(4)); -- tempdbの列情報確認
select
column_name as column_name
, data_type as type
, character_set_name as character_set
, collation_name as collation
, character_maximum_length as max_len
, character_octet_length as octet_len
from
tempdb.information_schema.columns;
insert into #t(vc) values ('—'); insert into #t(vc) values ('〜'); insert into #t(vc) values ('‖'); insert into #t(vc) values ('−'); insert into #t(vc) values ('¢'); insert into #t(vc) values ('£'); insert into #t(vc) values ('¬'); insert into #t(vc) values (N'—'); insert into #t(vc) values (N'〜'); insert into #t(vc) values (N'‖'); insert into #t(vc) values (N'−'); insert into #t(vc) values (N'¢'); insert into #t(vc) values (N'£'); insert into #t(vc) values (N'¬'); -- insertした内容の確認
select
vc
, len(vc) as length
, datalength(vc) as data_length
, cast(vc as varbinary(max)) as bin
from
where
vc is not null;
select
nvc
, len(nvc) as length
, datalength(nvc) as data_length
, cast(nvc as varbinary(max)) as bin
from
where
nvc is not null;
-- 同一セッション内で再実行する用にdrop
drop table tempdb.#t;
table:result
column_name type character_set collation max_len octet_len
vc varchar cp932 Japanese_CI_AS 4 4
nvc nvarchar UNICODE Japanese_CI_AS 4 8
table:result
vc length data_length bin
? 1 1 3F
? 1 1 3F
? 1 1 3F
? 1 1 3F
¢ 1 2 8191
£ 1 2 8192
¬ 1 2 81CA
? 1 1 3F
? 1 1 3F
? 1 1 3F
? 1 1 3F
¢ 1 2 8191
£ 1 2 8192
¬ 1 2 81CA
table:result
nvc length data_length bin
? 1 2 3F00
? 1 2 3F00
? 1 2 3F00
? 1 2 3F00
¢ 1 2 E0FF
£ 1 2 E1FF
¬ 1 2 E2FF
— 1 2 1420
〜 1 2 1C30
‖ 1 2 1620
− 1 2 1222
¢ 1 2 A200
£ 1 2 A300
¬ 1 2 AC00
それ以外は以下のようにinsertされる
1. ?になる
2. 全角に変換される
Shift_JISにあってCP932にない文字をinsertしようとしているのだから1.はわかる
暗黙的に2.をやっているのは何の設定なんだ…?
setで何か暗黙の変換をやっている設定はないか?
なさそう
照合順序関係ある?
関係ないか?直接指定して表示させようとするとnullになる
code:sql
select
nchar (162) collate japanese_ci_as /* UNICODEにU+00a2(半角¢) */
, nchar (65504) collate japanese_ci_as /* UNICODEにU+ffe0(全角¢) */
, char (37249) collate japanese_ci_as /* cp932にShift_JISの0x8191(半角¢) */
;
table:result
__COLUMN1 __COLUMN2 __COLUMN3
¢ ¢ « NULL »
やっぱりinsert, update時に裏で何かしてる?
Unicode文字データ型nchar、nvarchar、ntextを参照している場合は、'expression'の前に大文字の'N'を付ける必要があります。'N'が指定されていない場合、SQL Serverでは、文字列はデータベースまたは列の既定の照合順序に対応するコードページに変換されます。文字列がこのコードページにない場合は、失われます。 これはUNICODEの話だけど、コードページにない場合は失われるって書いてあるから、やっぱり?になるのはわかるんだよな
どうやって調べるんだ…?
実行計画を見てみる
code:xml
Version="1.6" Build="14.0.1000.169">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementText="(@1 varchar(8000))INSERT INTO t(vc) values(@1)" StatementId="1" StatementCompId="3" StatementType="INSERT"
RetrievedFromCache="true"
StatementSubTreeCost="0.0100022" StatementEstRows="1"
SecurityPolicyApplied="false"
StatementOptmLevel="TRIVIAL" QueryHash="0x5789..."
QueryPlanHash="0x3F93..."
CardinalityEstimationModelVersion="140">
<StatementSetOptions QUOTED_IDENTIFIER="true"
ARITHABORT="true"
CONCAT_NULL_YIELDS_NULL="true"
ANSI_NULLS="true"
ANSI_PADDING="true"
ANSI_WARNINGS="true"
NUMERIC_ROUNDABORT="false" />
<QueryPlan NonParallelPlanReason="NoParallelPlansInDesktopOrExpressEdition" CachedPlanSize="16" CompileTime="0" CompileCPU="0" CompileMemory="104">
<MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0" />
<OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="205213" EstimatedPagesCached="51303"
EstimatedAvailableDegreeOfParallelism="2" MaxCompileMemory="2047608" />
<TraceFlags IsCompileTime="1">
<TraceFlag Value="8017" Scope="Global" />
</TraceFlags>
<RelOp NodeId="0" PhysicalOp="Table Insert" LogicalOp="Insert" EstimateRows="1" EstimateIO="0.01"
EstimateCPU="1e-006" AvgRowSize="9" EstimatedTotalSubtreeCost="0.0100022" Parallel="0"
EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row">
<OutputList />
<ScalarInsert DMLRequestSort="0">
<DefinedValues>
<DefinedValue>
<ColumnReference Column="Expr1003" />
<ScalarOperator ScalarString="CONVERT_IMPLICIT(varchar(4),@1,0)"> <Convert DataType="varchar" Length="4" Style="0" Implicit="1">
<ScalarOperator>
<Identifier>
<ColumnReference Column="@1" />
</Identifier>
</ScalarOperator>
</Convert>
</ScalarOperator>
</DefinedValue>
</DefinedValues>
<Object Database="grafana" Schema="dbo" Table="t" IndexKind="Heap" Storage="RowStore" /> <SetPredicate>
<ScalarExpressionList>
<ScalarOperator>
<MultipleAssign>
<Assign>
<ColumnReference Database="grafana" Schema="dbo" Table="t" Column="vc" /> <ScalarOperator>
<Identifier>
<ColumnReference Column="Expr1003" />
</Identifier>
</ScalarOperator>
</Assign>
</MultipleAssign>
</ScalarOperator>
</ScalarExpressionList>
</ScalarOperator>
</SetPredicate>
</ScalarInsert>
</RelOp>
<ParameterList>
<ColumnReference Column="@1" ParameterDataType="varchar(8000)" ParameterCompiledValue="'¢'" />
</ParameterList>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>
実行計画の時点で¢は全角になっている
実行計画作成より前に変換されている?
〜をinsertしたときは実行計画の時点で?になっている code:xml
<ParameterList>
<ColumnReference Column="@1" ParameterDataType="varchar(8000)" ParameterCompiledValue="'?'" />
</ParameterList>
あ、すごい勘違いしていたかもしれない
そもそもShift_JIS→CP932に変換する時点で全角になってるんだ
insertより前だ
参考