- 締切済み
EXCEL 「並び替え」の誤動作について
WinXP/Excel2003 です。 大変お世話になります。 いまは定年退職し依頼されたExcelのアプリケーションなど 趣味で作っています。 今回、思わず躓いたのが「並び替え」です。 次のデータを昇順ソートすると あいざわ まさき おかだ りょうた おがた けいすけ 結果 あいざわ まさき おがた けいすけ おかだ りょうた となってしまいます。 五十音順では明らかに間違っています。 インターネットでいろいろ調べたんですが、 公式文書として以下がありました。 http://office.microsoft.com/ja-jp/word/HA102031991041.aspx だとしたら、みなさんどうやって回避してるのでしょう? これだと、全く使えないので、 なにか回避策、あるいは正しい設定方法があるのではないかと 想像してますが、ご存知の方、ご指導願えれば幸いです。
- みんなの回答 (6)
- 専門家の回答
みんなの回答
- fumufumu_2006
- ベストアンサー率66% (163/245)
ANo.4です。 >さてさて、では実際にどんなアルゴリズムにしようか、 >ちょっと悩みますね。 そういう仕事してませんが、私なら・・・ どれでもいいけど、基本的には楽な方。 更にはバグが出にくい方、コードが少ない方。 あとはクライアントが要望した場合、「うーん、結構難しいですねー」と言いながら、それに合わせる。 と言うスタンスが好きです。
- zap35
- ベストアンサー率44% (1383/3079)
#03です >でも、ちょっと重たいなぁ・・・ そうですね。データが何万件もあるのであればソートを何回も繰り返しますので遅くなるでしょう。 余計とは思いましたが、興味深かったので私もマクロを書いてみました。選択した範囲に対してふりがなでソートを行います。ソートHeaderの有無は自動判定にしていますので、表によってはタイトル行もソートされるかもしれません。 Sub PhoneticSort() Dim rng As Range, keyC Dim idxR, idxC, trgC As Long Const cols As Integer = 10 '挿入する作業列の数(=フリガナ文字数) Application.ScreenUpdating = False On Error GoTo end0 If TypeName(Selection) = "Range" Then Set rng = Selection keyC = Application.InputBox("ソートキーの列名を入力して下さい", Type:=2) If keyC = False Then GoTo end0 keyC = StrConv(keyC, vbNarrow) rng.Cells(1, 1).Offset(0, rng.Columns.Count).Resize(1, cols).EntireColumn.Insert For idxR = rng.Row To rng.Row + rng.Rows.Count - 1 For idxC = 0 To cols - 1 trgC = rng.Column + rng.Columns.Count + idxC Cells(idxR, trgC).Value = Mid(Cells(idxR, keyC).Value, idxC + 1, 1) Next idxC Next idxR trgC = rng.Column + rng.Columns.Count For idxC = trgC + cols - 1 To trgC Step -1 rng.Resize(rng.Rows.Count, rng.Columns.Count + cols).Sort _ key1:=Cells(rng.Row, idxC), order1:=xlAscending, header:=xlGuess Next idxC rng.Cells(1, 1).Offset(0, rng.Columns.Count).Resize(1, cols).EntireColumn.Delete End If end0: Application.ScreenUpdating = True End Sub なおテストしたデータは以下です(「データ」→「並び替え」の順番に並んでいます) Code Name Phonetic 1 座 頭くじら ざ とうくじら 2 座頭 くじら ざとう くじら 3 佐堂 賢二 さどう けんじ 4 佐藤 浩二 さとう こうじ 5 浜崎 あゆみ はまざき あゆみ 6 浜崎 歩 はまさき あゆむ これがマクロ実行後は Code Name Phonetic 4 佐藤 浩二 さとう こうじ 3 佐堂 賢二 さどう けんじ 1 座 頭くじら ざ とうくじら 2 座頭 くじら ざとう くじら 6 浜崎 歩 はまさき あゆむ 5 浜崎 あゆみ はまざき あゆみ になります。
お礼
例の方法を見事にコード化しましたね。 しかも短時間で・・・・ まったくレベルが違いますね。 コードの使い方が洗練されてるし、バグ対策も考慮されて・・ いいものを見せていただきました。 ありがとうございました。
- fumufumu_2006
- ベストアンサー率66% (163/245)
ANo.3さんのにダブりますが、漢字コード順がいいなら一時的に作業行に文字列の漢字コード(16進)を作っては? B列を作業列にして、A列を並び替えます。 Function sjis(k As String) As String Dim res As String Dim i As Integer For i = 1 To Len(k) res = res & Hex(Asc(Mid(k, i, 1))) Next sjis = res End Function Sub test1() Application.ScreenUpdating = False Dim ws As Worksheet Set ws = ActiveSheet Set ws = Sheet1 ws.Range("B1").Formula = "=sjis(A1)" ws.Range("B1").Copy Destination:=ws.Range("B1:B" & ws.Range("A" & ws.Rows.Count).End(xlUp).Row) ws.Cells.Sort Key1:=ws.Range("B1"), Order1:=xlAscending, Header:=xlNo ws.Columns("B").ClearContents Application.ScreenUpdating = True End Sub ただ、これだと小文字の「っ」とかはどうするのかと言うのがあるので、順番テーブルを用意する方法はどうでしょうか? 「ヴ」とかも処理できるように全角カタカナに変換しました。 テーブルに文字がないと文字が無かったと判断します。 256個以上は無いとして、2文字hexにしました。 個人的にはrange("?")よりcells(?,?)の方が好きなので・・・ Const kana = " 123456789" & _ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" & _ "アァイィウヴゥエェオォ" & _ "カガキギクグケゲコゴ" & _ "サザシジスズセゼソゾ" & _ "タダチヂツヅッテデトド" & _ "ナニヌネノ" & _ "ハバパヒビピフブプヘベペホボポ" & _ "マミムメモ" & _ "ヤャユュヨョ" & _ "ラリルレロ" & _ "ワヲン" & _ "ー().・" Function kanaOrder(ByVal k As String) As String Dim res As String Dim i As Integer Dim p As Integer k = UCase(StrConv(k, vbKatakana)) For i = 1 To Len(k) p = InStr(kana, Mid(k, i, 1)) If p > 0 Then res = res & Right("0" & Hex(p), 2) End If Next kanaOrder = res End Function Sub test2() Application.ScreenUpdating = False Dim ws As Worksheet Set ws = ActiveSheet ws.Cells(1, 2).Formula = "=kanaOrder(A1)" ws.Cells(1, 2).Copy Destination:=ws.Range(ws.Cells(1, 2), ws.Cells(ws.Cells(ws.Rows.Count, 1).End(xlUp).Row, 2)) ws.Cells.Sort Key1:=ws.Cells(1, 2), Order1:=xlAscending, Header:=xlNo ws.Columns(2).ClearContents Application.ScreenUpdating = True End Sub p.s. activesheetを並べ替えてますが、Set ws = sheets("??")とすれば、表示していないシートも並べ替えられます。
お礼
真っ向からのアルゴリズムですね。 (案1) HEX変換した文字列をSORTする (案2) コレートシーケンスを自作して、 その位置データに変換しsortする いずれも鮮やかですね。 ちなみにExcelのコレートシーケンスは 「ァアィイゥウヴェエォオ・・・」 のようですので、それはそれで、 案1で充分かと思いました。 大変勉強になりました。 貴重な時間をいただきありがとうございました。 今後ともよろしくお願いします。 さてさて、では実際にどんなアルゴリズムにしようか、 ちょっと悩みますね。 でも、最初に戻りますが、 清音=濁音=半濁音 とする、基本思想はなぜ必要になったのでしょうね? しかも、その結果「等価」の場合は、 吃音<清音<濁音<半濁音 とする こんなに複雑なコレートシーケンスはなぜ必要だったのか。 なにか深いわけがありそうですね。 (つぶやきです^^;) いずれにしても皆さんありがとうございました。
- zap35
- ベストアンサー率44% (1383/3079)
Microsoftの仕様には時々使いにくいものもありますね。Dor_001さんはマクロをお使いになるようですので、マクロを使えばこんな方法もあります(力業になります) 1)並べ替えしたいデータ範囲の右に、一時的にふりがなの最長文字列分の作業列を追加する 2)各列にふりがなを1文字分ずつ表示する 3)挿入した列の内、最後(右端)の列をキーにして並び替えする 4)またその前(左となり)の1列で並び替える(これを挿入した先頭列まで繰り返す) → ここまでで期待する並び順になるはず 5)作業列を削除する 画面描画はFalseにしておくとよいでしょう。マクロまでは書きませんが、その気があれば試してみてください。 ところでこの質問をお借りしますが http://oshiete1.goo.ne.jp/qa3890433.html はまだ解決しませんか? >上から順に行くのが現実的かと思いますので、 だとロジックが複雑になると思いますがいかがでしたでしょうか。
お礼
zap35さん、いつもお世話になっています。 昔はアセンブラー言語などでバブルソートやらクイックソートなど よく作りましたが、まさにその乗りですね。 このアルゴリズムでコード化すると正しい結果が出ますね。 でも、ちょっと重たいなぁ・・・ 「Justify」の件はやはり、最大領域の下位セル+1を起点として、 End(xlUp)を使わせてもらいました。 ありがとうございました。
- imogasi
- ベストアンサー率27% (4737/17070)
第1行にタイトル(例氏名)行を入れ(本質ではないが、リストというのが基本なので。) 中間にスペース(データなし)行を入れず フリガナを使わない、にチェックをいれ 大文字と小文字を区別するにチェックを入れ 行単位 でやってみてください。 うまくいくはずです ==== 文字コードに関心を持ったり、プログラム経験がない人はそう感じるかも知れませんが、コンピュターのソートは 文字コードで考えて 最左の桁から、ビット比較的に 比較して、勝負か付く(0ビットが勝、1のビットの方が巻け)ところまで比較を続け、1回目の勝負がついたところで決定(打ち切り)です。コンピュタの原初的仕組みです。 (上記は文字列の場合で、数値の場合は人間の大小の考えと、コンピュターの内部ビット表現が一致するよう定義されています。 動かしようがありません。) ーー 最近(1985年以後、パソコンなどから)エクセルなどのソフトなどからコンピュタに入り始めた人は ソフト側で裏で(便利なように)細工をしているので、ソートといえばそんな便利なものかと思いがちですが、修正ソートキーを裏で作って、それで自分(世間)の思うようにソートするようにしてるはずです。 ーー 結論は、コンピュタの基本原理は動かしようがないので、自分の思うように、逆手にとって、原ソートキーから、修正ソートキーを作らないとなりません。 ●レディメードで「フリガナを使う」 ●関数で別列に修正ソートキーを作る ●プログラムで修正キーを作る ほとんど3番目でないと出来ないでしょうが。 -- ただそんなに修正キーを作らなければならないケースは多くない。 前株後株、カ)など入力の多様化で、困ってしまって、必要になる場合が多い。 ーー スペースの問題 昔の半角かなの濁点・半濁点 の場合の扱いで、普通にソートすると、常識、慣用と異なる結果 ガ出るので、苦労した経験があります。 ーー 質問の点で、テスト的に =CODE("か")は 9259 =CODE("が")は 9260 になったので、同じ桁位置に2つがあれば、普通のソートでは、「か」が先に来ます。 (ただし昇順指定) ただ内部文字コードや色々あって各過程で使用文字コードが変化することがあるので、詳しい知識を必要とする場合があると思うが、文字コードの設計者は「か」を先(小さいコードで)に定義するはずです。
補足
丁寧で、かつご親切な解説をいただきありがとうございます。 ただ、 >第1行にタイトルを入れ >中間にスペース行を入れず >フリガナを使わない、にチェックをいれ >大文字と小文字を区別するにチェックを入れ >行単位 はすでにやってますが、 うまくいきませんでした。 なにか他にチェックしておかないといけない設定とかあるんでしょうか? 内部コードで単純比較してるのだったら、 このような結果は出ずに、 素直に正しい結果が出るのと思うのですが、 ご説明のように、 なにか、小細工してるようですね。 それが何のためなのかよくわからないところです。 そして、それがむしろ足を引っ張っているような気がします。 VBAでの一連の処理の流れの中のSORTなんですが、 処理前に、姓名の「名」の方を削除して、 SORT後、処理がすべて終わった段階で「名」を付加してます。 手作業です。
- ganko3
- ベストアンサー率67% (118/174)
テストしてみたら次の順序で並びました。 おか おが おかた おかだ おがた おがだ おかたけ おかだけ おがたけ おがだけ おかたり おかだり おがたり おがだり 清音、濁音の順序より後ろの字のほうが優先されるようですから、ご希望のように並べるには、姓と名を分けてまず姓で次の優先順位が名で並び変えたらよいと思います。
補足
回答ありがとうございます。 ただ、このやり方だと、姓・名として2列 必要となります。 本来は1列で管理すべきデータと思いますので、 ソートの前後等で、余計な処理が必要となります。 ganko3さんの方法で逃げるしかないとしたら、 みなさん不便を感じてないのでしょうか?? Microsoftともあろうものが、どうも納得できないですね。 仕様と言われればそれまでなんですが・・・ 直す気はさらさらないのでしょうかね? その辺の理由なんか知りたいですね。
お礼
コード作成は最終的に個人的な審美眼によるものだと思います。 最低条件として、 バグ、速度、コード量(メモリー)だと思いますが、 最近はメモリーが安いので、バグ、速度のウェイトが高いでしょうね。 たぶん、HEX文字列に変換するワークシート関数(sjis)を作成し、 それをsort対象のワークシートの空き列に定義し、 従来のVBAのコードのsort範囲とsortキーを変更する程度の改修を考えています。一番楽でバグが少ない方法かと思います。 fumufumu_2006 さんのコードもなかなか洗練されていて、 さすがだな・・と思いました。 こんなコードがすらすら書けるようになりたいものです。 大変ありがとうございました。