エクセル雑感
サロゲートペアに対応した自作関数(Len,Left,Mid,Right)

ExcelマクロVBAとエクセル関数についての私的雑感
最終更新日:2022-06-24

サロゲートペアに対応した自作関数(Len,Left,Mid,Right)


ツイッターで、サロゲートペアに対応した文字列関数の話しになりました。


シート関数のLEFTとRIGHTはサロゲートペアに対応しているようですが、MIDとLENは対応していません。
そして、VBA関数の、Len,Left,Mid,Right、これらは一切サロゲートペアに対応していません。
これが必要になることもほとんどないのですが、ツイッターで話したついでなので関数を自作してみました。

こういういきさつなので、特に凝ったVBAを作成したわけではありませんし、厳密なテストもしていません。
とりあえず作って見たので、残しておく意味でここに掲載しておくことにしました。


サロゲートペアとは

簡単に言うと、UNICODEの2文字分で1文字を表すものです。
通常2バイトで1文字のところ、4バイトで1文字になっています。
𩸽
𠮟
これらはサロゲートペア文字です。

※サロゲートペアについての詳細はネットで検索してください。


4バイトを超えるマルチバイト文字

4バイトでも足らなくて?、さらにもっと多くのバイト数を使っているものもあります。
🙇‍♂️
🙅‍♂️

今回は、これらには対応していません。
もう、ここまでくると、わけわからない・・・


サロゲートペアに対応した文字列関数のVBA

以下2通り書いてみて、どちらが良いとも言えないので、両方残すことにしました。



Function xLen(ByVal s As String) As Long
  Dim i As Long, cnt As Long
  i = 1: cnt = 0
  Do While i <= Len(s)
    If i < Len(s) Then
      If isSurrogatePair(Mid(s, i, 2)) Then
        i = i + 1
      End If
    End If
    cnt = cnt + 1
    i = i + 1
  Loop
  xLen = cnt
End Function

Function xMid(ByVal s As String, ByVal st As Long, Optional ByVal ln As Long = 0) As String
  If ln = 0 Then ln = Len(s)
  Dim cnt As Long
  cnt = 1
  Do While xLen(Left(s, cnt)) < st And cnt <= Len(s)
    cnt = cnt + 1
  Loop
  Do While xLen(xMid) < ln And cnt <= Len(s)
    xMid = xMid & Mid(s, cnt, 1)
    If cnt < Len(s) Then
      If isSurrogatePair(Mid(s, cnt, 2)) Then
        xMid = xMid & Mid(s, cnt + 1, 1)
        cnt = cnt + 1
      End If
    End If
    cnt = cnt + 1
  Loop
End Function

Function xLeft(ByVal s As String, ByVal ln As Long) As String
  xLeft = xMid(s, 1, ln)
End Function

Function xRight(ByVal s As String, ByVal ln As Long) As String
  xRight = xMid(s, xLen(s) - ln + 1)
End Function

Function isSurrogatePair(ByVal s As String)
  Dim b() As Byte: b = s
  Dim h1 As Long, h2 As Long
  isSurrogatePair = False
  h1 = b(0) + b(1) * 256&
  h2 = b(2) + b(3) * 256&
  If h1 >= &HD800& And h1 <= &HDBFF& And _
    h2 >= &HDC00& And h2 <= &HDFFF& Then
    isSurrogatePair = True
  End If
End Function




Function xLen(ByVal s As String) As Long
  Dim b() As Byte: b = s
  Dim i As Long
  For i = LBound(b) To UBound(b) Step 2
    If isSurrogatePair(b, i) Then
      i = i + 2
    End If
    xLen = xLen + 1
  Next
End Function

Function xMid(ByVal s As String, ByVal st As Long, Optional ByVal ln As Long = 0) As String
  If ln = 0 Then ln = Len(s)
  Dim b() As Byte: b = s
  Dim bOut() As Byte, iOut As Long
  Dim i As Long, j As Long, cnt As Long

  For i = LBound(b) To UBound(b) Step 2
    cnt = cnt + 1
    If cnt >= st Then
      For j = i To i + IIf(isSurrogatePair(b, i), 3, 1)
        ReDim Preserve bOut(iOut)
        bOut(iOut) = b(j)
        iOut = iOut + 1
      Next
    End If
    If xLen(bOut) >= ln Then Exit For
    If isSurrogatePair(b, i) Then i = i + 2
  Next
  xMid = bOut
End Function

Function xLeft(ByVal s As String, ByVal ln As Long) As String
  xLeft = xMid(s, 1, ln)
End Function

Function xRight(ByVal s As String, ByVal ln As Long) As String
  xRight = xMid(s, xLen(s) - ln + 1)
End Function

Function isSurrogatePair(ByRef b() As Byte, ByVal i As Long)
  Dim h1 As Long, h2 As Long
  isSurrogatePair = False
  If i > UBound(b) - 3 Then Exit Function
  h1 = b(i) + b(i + 1) * 256&
  h2 = b(i + 2) + b(i + 3) * 256&
  If h1 >= &HD800& And h1 <= &HDBFF& And _
    h2 >= &HDC00& And h2 <= &HDFFF& Then
    isSurrogatePair = True
  End If
End Function




同じテーマ「ツイッター出題&回答」の記事

Rangeオブジェクトを受け取り"行数,列数"で埋める
数式の関数の使用回数、関数名を配列で返す
キーボード操作だけで非表示列を表示
日付型と通貨型のValueとValue2について
小文字"abc"を大文字"ABC"に変換する方法
連番を折り返して出力
4,9を使わない連番作成
コメントから特定形式の年月を取り出す
オブジェクトのByRef、ByVal、Variant
「マクロの登録」で登録できないプロシージャーは?
サロゲートペアに対応した自作関数(Len,Left,Mid,Right)


新着記事NEW ・・・新着記事一覧を見る

サロゲートペアに対応した自作関数(Len,Left,Mid,Right)|エクセル雑感(2022-06-24)
「マクロの登録」で登録できないプロシージャーは?|エクセル雑感(2022-06-23)
オブジェクトのByRef、ByVal、Variant|エクセル雑感(2022-06-22)
コメントから特定形式の年月を取り出す|エクセル雑感(2022-06-19)
4,9を使わない連番作成|エクセル雑感(2022-06-17)
連番を折り返して出力|エクセル雑感(2022-06-16)
VBAの基礎・基本の要約|VBA入門(2022-06-14)
ピッボットテーブルって便利だよね|還暦のVBA(2021-10-18)
還暦のVBA:VBAまでたどりつけるか… (2021-09-29)
VLOOKUPを使うことを基本としてシートを設計すべきか|エクセル雑感(2021-08-17)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.Excelショートカットキー一覧|Excelリファレンス
6.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
7.マクロって何?VBAって何?|VBA入門
8.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
9.並べ替え(Sort)|VBA入門
10.エクセルVBAでのシート指定方法|VBA技術解説




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ