プロが教えるわが家の防犯対策術!

いつもお世話様です。
エクセルVBAでFormatを使うと、文字列中にeが一つ入っていると、「指数」とみなされて勝手に数値に化けてしまうようです。
話を簡単にするため、問題のコートを簡易化したコードが下記のtest1です。
入力されるのは常に3文字以内の英数です。

test1のコードは、ab9と入れればAB9、01とか20とか入れると、予定通り001や020を返してくれます。
ところが、なかには1E1や4E3なども入力する必要があり、これを入れると010や4000に化けてしまいます。
現在は、対処するため、下記test2のように、文字列中に"E"があるかどうかで処理を分岐させていますが、ほかに何か良い方法はないでしょうか?

Sub test1()
Dim x As String, y As String, z As String
x = Application.InputBox("CODEを入力してねん。", Type:=2)
y = StrConv(StrConv(x, vbUpperCase), vbNarrow)
z = Format(y, "000")
MsgBox z & " Typeだよ。"
End Sub

Sub test2()
Dim x As String, y As String, z As String
x = Application.InputBox("CODEを入力してねん。", Type:=2)
y = StrConv(StrConv(x, vbUpperCase), vbNarrow)
If InStr(y, "E") > 0 Then
z = y
Else
z = Format(y, "000")
End If
MsgBox z & " Typeだよ。"
End Sub

A 回答 (6件)

エキスパートさん、こんにちは。



FORMAT関数をまだ自分のものにしておりませぬね。
と、ちょっときついことを言ってみる。(^^;;;

Format(y,"000") は、数値表示書式指定文字を使ってますから
文字列1E2(10^2)も数字になります。

質問には英数混合3桁の例で、ab9 とありますが
英数混合で3桁未満はどう表示するのでしょうか?

 ab → 0AB  → ■AB  → AB
 b  → 00B  → ■■B  → B
 1a → 01A  → ■1A  → 1A

■はスペース

3桁未満の表示の仕方によっては、#1の回答も
単純には使えないことはお分かりですね。

(おまけ)
いまのままで 1a とか 1p を試したみてください。

何れにしろ分岐が必要になると思われます。
以上です。

 
    • good
    • 0
この回答へのお礼

これはこれは、kobouzu_su様、いつも有難うございます。
1a とか 1p も化けるんですね!亜茶^2!!
これは指数じゃないですよね?な、なんなのでしょう?
先頭に0をつけるのはあくまで数字だけの場合ですので1Aや1Pはそのまま表示されればいいのです。

試行錯誤の結果、以下のように対応しましたがこれで正解でしょうか?

Sub test5()
Dim x As String, y As String, z As String
x = Application.InputBox("CODEを入力してねん。", Type:=2)
If Len(Trim(x)) > 3 Then
MsgBox "そんな長いTypeCode知りませぬ。", vbCritical, " (; ´・ω・`)σ" & x
Exit Sub
End If
y = StrConv(StrConv(x, vbUpperCase), vbNarrow)
z = IIf(IsNumeric(y), Right$("000" & y, 3), y)
MsgBox z & " Typeだよ。", , " ( ̄ー ̄)v "
End Sub

お礼日時:2007/06/18 17:18

エキスパートさん、こんにちは。



>Trim関数は文字列の先頭と末尾のスペースだけ削除するんですよね
>なら真中の■に影響ないのでは?

(■はスペース)

2■5 → 025 

と変換したい場合は問題ありですよね、ということでした。
3桁未満の数字の頭には、0を付けるということでしたので。
そうでなければ問題なしです。

何れにしろ数値を判定させるのはなかなかのものですね。
以上です。
 
    • good
    • 0
この回答へのお礼

kobouzu_suさま、有難うございました。
ご迷惑でしょうが、これからも末永くご指導くださいませ。

お礼日時:2007/06/19 13:44

> Eは指数表示というのは存じてましたが、Dは何なのですか?



「D」も「E」もともに指数を表しています。両者の違いは、

 ・E  有効桁数が Single(単精度)の指数
 ・D  有効桁数が Double(倍精度)の指数

です。

> 1Pや1Aもわかりません。

これは IsNumeric の問題ではありません。Format の問題ですね。
こちらについては、kobouzu_su さんが詳しく回答なさってます。

以下は余談までに。

IsNumeric 関数は仕様として、指数表記の文字、小数点、桁区切り
のカンマなども数値として評価します。

つまり、、

IsNumeric 関数はあくまで「数値として評価できるか」を判定する
関数であって、判定対象が必ずしも数字で構成されていることを
保証しません。

これはこれで都合が良いことも多いのですが、例えばデータベース
絡みの処理を考えてみると、整数フィールドに値を代入する SQL
を発行する場合に、指数表記の文字などが混入すると SQL でコケ
るか、間違った値が保存されてしまいます。
単純に IsNumeric でしか入力チェックしてないとスルーしちゃうん
ですね...

このような心配があるときは、#3 の参考 URL にある IsDigit の
ような自前関数を作ってチェックを行う必要があります。

IsNumeric にバグがある訳ではなく、あくまで仕様なのですが、
このことを理解していないと、思いもよらない結果を返すという話
になってしまいます。

 # 同じように IsDate 関数も英語表記の日付式で True を返します。

結局は、仕様を良く理解した上で利用する...「上手に使え」という
ことになってしまうのですが^^;

ご参考までに、正規表現を使った例です。

Sub test6()
  Dim x As String
  Dim y As Variant
  
  x = Application.InputBox("CODEを入力してねん。", Type:=2)
  v = CheckCode(x)
  If VarType(v) = vbBoolean Then
    MsgBox "(; ´・ω・`)σ不正値みたい", vbCritical
  Else
    MsgBox CStr(v) & " Typeだよ。", vbInformation, " ( ̄ー ̄)v "
  End If
  
End Sub

' // Code チェック関数
Private Function CheckCode( _
    ByVal sCode As String _
) As Variant
  
  ' // コードの長さ(文字数)
  Const MAX_DIGIT As Long = 3&
  
  CheckCode = False
  ' // 引数 sCode が3文字より多ければ終了
  If Len(sCode) > MAX_DIGIT Then Exit Function
  
  ' // 前後の不要スペース除去・半角大文字に補正
  sCode = Trim(sCode)
  sCode = StrConv(sCode, vbUpperCase Or vbNarrow)
  
  ' // 正規表現で入力チェック
  Dim reg As RegExp
  Set reg = CreateObject("VBScript.RegExp")
  reg.Pattern = "^[0-9]+$"
  If reg.test(sCode) Then
    ' // Return: 数字のみの場合-->桁数補正
    CheckCode = Right$(String$(MAX_DIGIT, "0") & sCode, MAX_DIGIT)
  Else
    ' // Return: 数字以外が含まれる場合
    ' //     規定の文字以外がないかチェック
    reg.Pattern = "^[0-9A-Z]+$"
    If reg.test(sCode) Then
      CheckCode = sCode
    End If
  End If
  Set reg = Nothing

End Function
    • good
    • 0
この回答へのお礼

KenKen_SPさま、ご丁寧に有難うございます。
「正規表現」というのはまったく馴染みがないのですが、これもいずれ勉強したいと思います。

今回も有難うございました。

お礼日時:2007/06/19 09:50

またまた登場、kobouzuです。

(^o^)/

KenKen_SPさんまで登場してくださるとは、エキスパートさんはなんと幸せものでしょう。
鬼に金棒とは、こういう状況を言ふのですよねぇ。
あと、一人、登場されると、金棒2本ですね。
ということで、当方への質問のみの返答ということで。
2a と 3p とかと、Format(y,"000")の関係について。

以下をお試しください。

Sub test()
 Dim y
 y = "2a"  ''' y = "5p"
 Range("A1").Value = Format(y, "0.0000000")
 Range("A2").Value = Format(y, "0.0000000")
 Range("A2").NumberFormat = "hh:mm:ss"
End Sub

どうでせしょう。お分かりになりましたか?

それから、
>If Len(Trim(x)) > 3 Then

>y = StrConv(StrConv(Trim(x), vbUpperCase), vbNarrow)

Trimはあまり感心しませんね。
2■5 とかが上手くいかないですよね。

それと細かいことですが、vbUpperCase,vbNarrowは次のように
y = StrConv(????, vbUpperCase+vbNarrow)
と、+で結合して使うのがふつうです。

以上です。
 
    • good
    • 0
この回答へのお礼

kobouzuさま、いつも有難うございます。
素晴らしい知識のみなさまに教えていただき「質問のエキスパート」?は非常に助かっております。

IsNumericではFalseになるけど、Formatすると、2Aは午前二時、3Pは午後3時なんですね!初めて知りました。おどろきました。

> Trimはあまり感心しませんね。
> 2■5 とかが上手くいかないですよね。

すみません、これはちょっとわかりませんでした。
■は、スペースの意味ですか?
Trim関数は文字列の先頭と末尾のスペースだけ削除するんですよね?なら真中の■に影響ないのでは?それとも他の問題でしょうか?

MsgBox StrConv("abc", vbUpperCase + vbNarrow) と、+で結合して使えるんですね!!これも初めて知りました。おどろき^2 です。

お礼日時:2007/06/19 09:40

こんにちは。



どうせならもう一歩踏み込んでみては?

[つっこみ] IsNumeric だけでは不十分(意地悪じゃないですよ^^;)

  例).12、+12、-12、!!!

[ご提案] 規定の文字以外を弾くチェック関数を作ってみては?

  ・方法1: 正規表現を使ってみる
        CreateObject("VBScript.RegExp")
        Test メソッド
        マッチングパターン: [0-9A-Z]{,3}
       
  ・方法2: 一文字ずつ Mid で取り出して判定
        Like 演算子を使ってみる、または文字リストを作っておき、
        それと比較する
        文字列長は3文字判定しておく

[参考URL:]
http://homepage1.nifty.com/rucio/main/technique/ …

この回答への補足

すみません。勘違いでした。お礼で書いたABSは使えませんね。
また3D2や3E2もFALSEではなくTRUEでした。
ただ、1Pや1AはFALSEです。

Dは何なのですか?また1Pや1Aも何なのでしょうか?という質問です。
よろしくお願いいたします。

補足日時:2007/06/18 23:20
    • good
    • 0
この回答へのお礼

ご指摘有難うございました。いろいろ問題ありますねえ!
今回は、Typeの誤入力を防ぐ方法ではなく、入力した1E1等がが化けることが問題なので.12、+12、-12は特に差し支えありません。(一応ABSで対処はしましたが)

参考URLを見ましたが、Eだけじゃなく3D2のようなのも数値に化けるんですね!これは問題です。Eは指数表示というのは存じてましたが、Dは何なのですか?さきほどの1Pや1Aもわかりません。よろしかったらご教示ください。

また、参考URL ではIsNumericでTRUEとなると書かれた3D2や3E2が下記のコードではFALSEとなるようですが何故でしょうか?

Sub test6()
Dim x As String, y As String, z As String
x = Application.InputBox("CODEを入力してねん。", Type:=2) ')
If Len(Trim(x)) > 3 Then
MsgBox "そんな長いTypeCode知りませぬ。", vbCritical, " (; ´・ω・`)σ" & x
Exit Sub
End If
y = StrConv(StrConv(Trim(x), vbUpperCase), vbNarrow)
If IsNumeric(y) Then
z = Right$("000" & Abs(y), 3)
Else
z = y
End If
MsgBox z & " Typeだよ。", , " ( ̄ー ̄)v "
End Sub

お礼日時:2007/06/18 22:36

素直に


z = Right$("000" & y, 3)
ではどうですか?
    • good
    • 0
この回答へのお礼

阿茶!
そうかあ、何もFormatする必要がなかったんだぁ!

・・・でも、目からうろこです。
有難うございました。

お礼日時:2007/06/18 14:30

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています