Function splith(str As String, n As Long) As String()
'//ANSI(半角1バイト、全角2バイト)を利用してnカウント以内で分割した文字列の配列を返す関数
Dim strBase As String, strAnsi As String, str1 As String, str2 As String, strLeft As String
Dim sCount As Long
Dim strSplit() As String
strBase = str
Do Until strBase = ""
ReDim Preserve strSplit(sCount)
strAnsi = strConv(strBase, vbFromUnicode)
'//合計nカウント以内だったらそのまま取り出して終わり
If LenB(strAnsi) <= n Then
strSplit(sCount) = strBase
Exit Do
End If
'//nカウント目の文字をチェックして2バイト文字なら切り捨てる
str1 = strConv(LeftB(strAnsi, n), vbUnicode)
str2 = strConv(LeftB(strAnsi, n + 1), vbUnicode)
If Len(str1) = Len(str2) Then
'//2バイト文字から1バイト取り出したら文字数は1(文字は化けるが文字数は1)
'//余分に1バイト取り出しても正常な文字として文字数は1で、全体の文字数は変わらない
'//nカウント目の文字が2バイト文字の前半1バイトだったので1バイト減らす
strLeft = strConv(LeftB(strAnsi, n - 1), vbUnicode)
Else
'//余分に1バイト取り出して文字数が変わったらnカウントでちょうど文字の区切りだった
strLeft = str1
End If
'//取り出した文字を配列に保存
strSplit(sCount) = strLeft
'//取り出した文字分だけ元の文字を取り除く
strBase = Mid(strBase, Len(strLeft) + 1)
'//配列の次の要素の準備
sCount = sCount + 1
Loop
splith = strSplit()
End Function
テストコード
Private Sub コマンド0_Click()
Dim strBase As String
Dim strSplit() As String
Dim sCount As Long
strBase = Me!テキスト
If strBase = "" Then Exit Sub
If strBase <> strConv(strConv(strBase, vbFromUnicode), vbUnicode) Then
MsgBox "非対応の文字が見つかりました。処理を中断します"
Exit Sub
End If
strBase = strConv(strBase, vbNarrow)
strSplit() = splith(strBase, 20)
For sCount = 0 To UBound(strSplit)
Debug.Print strSplit(sCount)
Next
End Sub
Public Function MidAnsiB(S As String, M As Long, L As Long) As String
Dim res As String, T As Long
If S = "" Then Exit Function '元テキストが空なら終了
If LenAnsiB(S) <= L Then '元テキストが任意の数以下ならそのまま出力して終了
MidAnsiB = S
Exit Function
End If
res = StrConv(MidB$(StrConv(S, vbFromUnicode), M, L), vbUnicode) 'コードを変えて文字数揃えてユニコードに戻す
res = Mid$(S, M, Len(res))
If LenAnsiB(res) > L Then
res = Mid$(S, M, Len(res) - 1)
End If
'サロゲートペア文字対策
Select Case AscW(Right$(res, 1))
Case &HD800 To &HDBFF
res = Left$(res, Len(res) - 1)
End Select
MidAnsiB = res
End Function
Private Sub cbo送付先企業ID_Enter()
If Me.chk未登録 = True Then
Else
Me.cbo送付先企業ID.Requery
End If
End Sub
Private Sub txt送付先企業_Enter()
If Me.chk未登録 = True Then
Else
Me.cbo送付先企業ID.SetFocus
End If
End Sub
Private Sub cbo氏名ID_AfterUpdate()
Me.cbo氏名ID.Requery
If Me.txt住所1 = "" Then
MsgBox "住所が入力されていません。"
ElseIf Me.txt郵便番号 = "" Then
MsgBox "郵便番号が入力されていません。"
End If
End Sub
バッチリうまくいきました。ありがとうございます😊
txtB
は「txtB」という名前のコントロール(またはフィールド)そのものを参照します。コントロール名を動的に生成して参照するなら、文字列を受け取ってコントロールを参照するようなアクションを使う必要がありますそれと、計算順の問題で数値部分は先に計算させる(括弧で囲む)必要がありますね
更に初心者の質問で申し訳ありません。
Debug.Print strSplit(sCount)
の部分についてですが、テキストボックスに1個ずつ格納していきたいと思っています。
テキストボックス名 txtB & scount + 1 として
txtB & sCount + 1 = strSplit(sCount)
というのは、不可能のようですね。。
変数名のカウントアップはどうしたらよいのでしょうか。
大変悩んでいたので本当に助かります。
じっくり内容を確認し、勉強させていただきます!!本当にうれしいです。
ありがとうございます。
hatenaさん
返信ありがとうございます。
Excel
新規ブックを開いて、
A1セルに 00LJ と入力
B2セルに AU87 と入力
上記のセルをそれぞれコピーして、Accessのテーブルのフィールドに貼り付け
⇒上記手順を試したところ、新規で作成したエクセルのデータは問題なく貼付できました。
使用しようとしているエクセルデータの方に、何かしら問題があるのかもしれません。
エクセル側データを今一度確認し、問題がないようなら、
0始まりおよびアルファベットから始まるフィールドが関与しない方法で
クエリを作成するなど他の対応方法を検討してみます・・・
とりあえずUnicodeのことは忘れて、次の例を考えます。
この場合、たとえば
Midh(str, a, b)
のような関数を作ったとしてMidh("あイうエお", 5, 3)
としたとき、「う」はどう扱ったらいいでしょうか?半角を1、全角を2とカウントするようなMidのような関数は現実的ではないでしょう
このようなことをする場合は、すべての文字をひとくくりに考える必要があります
半角を含む文字列を処理する関数「splith()」
テストコード
出力結果
ありがとうございました。
全然違いますね。。
他も試してみたのですがやはりうまく行きません😓
Len(M)の間違いでした。。
あと、初心者で申し訳ないのですが、
$マークは、どういう意味があるのでしょうか?
お騒がせしております。
今気づいたのですが、
res = Mid$(S, M, Len(res))
が
res = Mid$(S, LenAnsiB(M), Len(res))
でしょうか。。
あとで試してみます。
ID 毎の標準偏差を求めたいなら、クエリのデザインビューは下記にしてください。
ID以外のフィールドをグループ化しますと、グループ内件数が1件になってしまうので標準偏差は求められません。
SQLなら、
連結にしていましたが、[元テキスト]⇒txt元テキスト ・・・等々変更したら1回で表示されるようになりました。教えていただきありがとうございました。
反映させる部分↓
ありがとうございます。教えていただいた関数を参考に考えていますが、
行き詰っています。
今回文章を何個かに分割したいので、midで作って繰り返しさせたいと思っていますがうまくいきません・・・
どこが間違っているのでしょうか。
(とりあえず汎用関数の部分のみ↓)
全角、半角に関しては、いろいろ複雑な事情があります。
とりあえず下記を参照してください。
半角1桁全角2桁で計算するLenB、LeftB関数の代替関数 - hatena chips
VBA Unicode 文字の入力や変換、読み込みについて
Unicode文字(Shift-JISにない文字)、サロゲートぺー文字の扱いはどうするのかまずは決める必要があると思います。
フォームは連結ですか、非連結ですか。
一応、非連結で下記のようなサンプルを作成して確認してみましたが、ボタン1回クリックで表示されました。
テキストボックス
コマンドボタン
この件ですが、21バイトだった場合19バイトで切り出したらいいですね・・
式を考え中ですが、また相談させていただくと思います。すみません。
5の質問について、解決法がわかれば助かります。
もう1つの質問を記載させていただきます。
現在以下のように、[テキスト]の文章を20バイトで区切ってテキストボックスで3つに分けるという処理をしています。
このとき、うまく20バイトずつ文章が分かれてくれたらいいのですが
全角と半角が混ざった文章だと、文字化けしたり21バイトになったりします。
20バイト以下で、文字化けせずにうまくわけることはできませんでしょうか。
以上、ご検討いただければ幸いです。宜しくお願い致します。
下記コードで半角化&文字数を表示することができました!
ありがとうございました。
次の質問なのですが、現在ボタンを2回押さないと反映できません。
(それを解消できるかと思って「Me.Refresh」を2回入れているのですが・・だめでした)
1回で反映できる方法はありますでしょうか。
半角化じゃなかった、文字コードの変更をすると文字化け、の間違いです。スミマセン。
すみません。書きかけでエンターを押してしまいました。
下記コードで半角化すると文字化けしますが、こちらは今までどおりの式にして
カウントだけ変更すればよいでしょうか、今から試してみます。
ありがとうございます。とても参考になったのですが、うまく行きません。
Len 関数
その文字に何バイト使うか?というのは文字コードに依存します。(LenB関数の埒外)
String Data Type (Visual Basic)
VBAで文字を扱おうとすると基本、Unicodeで扱われます。Unicodeは半角、全角関係なく1文字を2バイトで表現する文字コードです。
半角カナ
いろいろあって、濁音や半濁音を表すときは2文字使うというのが現在です。
以上のことから質問の、
の例では4文字×2バイト増えた数字が表示されるのです。
半角1文字を1、全角1文字を2とカウントするためには、そう表現する文字コードに変換してLenB()を使う必要があります。最初のリンク先にある通り
のような処理をさせます。
表示/非表示の切り替えは、Visibleプロパティで可能です。
AccessVBAの基本8~可視・使用可能プロパティの変更
ご検討ありがとうございます。
そうですよね。申し訳ありません。
実際のファイルを送ることができないので、時間ができたら簡単なものを作ってみたいと思います。その前に、本件に関する別件で質問です。
(この件もファイルを送らないと伝わりづらかったら申し訳ありません、その場合は改めます)
上記コードの1つ目の件で、登録された企業はコンボボックスとテキストボックスを切り替えて表示しているのですが、未登録企業チェックを入れたときコンボボックスにロックをかけますが、表示されてしまうので紛らわしい状態です。(タブストップも適用される)
コンボボックスを非表示にすることはできますか?
現状ですと、どこのレコードソースを変更するのか分からない状態になっているかと思います。
フォームBのレコードソースを変更したい場合には下記になるかと。
またSelect Caseに対応するEnd Selectがありませんので、
別のエラーも出ていると思います。
可能なら、実際のファイルを見せてもらった方が速いです。
コードだけでは全体像がつかめないし、出ている情報だけからサンプルを作成して動作確認するのもちょっと困難なので。
右カラムの下の方にあるファイル送信フォームから現状のファイルを送信てもらえませんか。
テーブルデータは個人情報も入っていると思いますので、削除しておいてください。
早速の質問恐れ入ります。
まず、企業名はコンボボックスだったため以下設定にしてみました。(正しいでしょうか…?)
そして、チェックをつけたりはずしたりした時の挙動がよくわからなかったので
実行のタイミングをチェックボックス更新にしてみました…問題ありますでしょうか。
そして今困っている点です。チェックボックスを切り替えたとき、
不要な情報を消したいのですが、色々エラーが出てうまくいきません。。
まだ作成途中なので、これらの設定では今後不具合が出てくるのかもしれませんが
とりあえずチェックボックスの切替で悩んでいる状況です。
そのエラーがでるとき「F管理総合」フォームは開いてますか。
あるいは「F管理総合」がサブフォームということはないですか。
コンボボックスはフォームヘッダーに配置しているのですか。
フォームは帳票フォームですか。
フォームで新規レコードを入力できますか。
コンボボックスの値集合ソース、値集合タイプの設定を提示してください。
下記の手順で確認してみましたが、再現できませんでした。(普通に貼り付けできました。)
Access
テーブルを新規作成して、
データ型:短いテキスト
書式:@
のフィールドを追加
Excel
新規ブックを開いて、
A1セルに 00LJ と入力
B2セルに AU87 と入力
上記のセルをそれぞれコピーして、Accessのテーブルのフィールドに貼り付け
とりあえず、上記の手順をそちらでやってみてブランクになるという現象が発生しますか。
ありがとうございます!
テキストボックスを切り替えることができるのですね!!すごい。
理解できたつもりですが、作成してみてわからないところがでてきたら改めて質問させていただきたいと思っています。
申し訳ありませんが、その際は宜しくお願い致します。
また、色々考えている内に本件について追加の欲望もでてきたので、その件も行き詰ったら質問させていただきたいと思っております。すみません。
不足している情報は勝手に推測して、テーブルは下記と仮定します。
T送付履歴
送付ID、発送日、会社ID、送付資料1、送付資料2、・・・
T会社情報
会社ID、会社名、部署名、郵便番号、住所1、住所2、・・・
先頭のフィールドが主キー
T送付履歴 に下記のフィールドを追加します。
仮(Yes/No型)、仮会社名、仮部署名、仮郵便番号、仮住所1、仮住所2
上記のテーブルからクエリを作成してフォームのレコードソースとします。
フォームは単票フォームとします。
会社名、部署名、郵便番号、住所1、住所2 のフィールドはテキストボックスとしてフォーム上に配置します。
「編集ロック」は「はい」にしておきます。(マスターが不用意に更新されないようにするため)
また、フィールドの追加やウィザードで配置したテキストボックスの名前はフィールド名と同じになっているので、それぞれの名前を、
txt会社名、txt部署名、txt郵便番号、txt住所1、txt住所2 というように変更しておきます。
あと「仮」フィールドもフォーム上に配置します。Yes/No型なので、チェックボックスになります。
フォームのモジュールに下記のイベントプロシージャを作成します。
これで、仮チェックボックスにチェックを入れると、会社名、住所等を入力できるようになり、
仮会社名、仮住所1 ・・・に格納されます。
レポートでは、例えば会社名のテキストボックスのコントロールソースは、下記のように設定します。
=IIf([仮]=True,[仮会社名],[会社名])
以上、一例です。
度々スミマセン。結局自己解決しました。
現在は郵送履歴は残していませんでしたが、残したいと思っていたので
先程記載した現状のフィールドに「発送日」も追加予定です。
フォームは帳票にしていますが、よく考えたら単票でもいいです。
都合の良い方で宜しくお願い致します。
ご確認ありがとうございます。「F送付」のレコードソースはクエリになっています。
住所等の情報は「T会社情報」にあり、「Q送付」にひっぱっています。
Q送付のフィールド名は 送付ID、郵便番号、住所1、住所2、会社ID、会社名、部署名、氏名ID、氏名、送付資料1、送付資料2・・
といった感じです。
「普段は登録している企業を選択したら情報を引っ張ってくる」についてですが、
「F送付」の「cbo氏名ID」にて氏名を選択すると以下VBAが動きます。
フォームは帳票です。
アイデアがあるとうれしいです。ご検討ありがとうございます。
hatena様大変ありがとうございました。
ごめんなさい。修正して絞り込んだらうまく行ったとおもったのですが、勘違いでした。。
改めて、下記コードの修正部分を教えていただけると助かります。
Access上でしばらく悩んでいたので投稿したのですが、記載した途端間違いがわかりました。。
※orの部分を大かっこで囲む
スミマセン。お騒がせしました。