質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

3回答

3736閲覧

セルの値から新規にシートを作成する。ただし既にセルの値と同じ名前のシートがある場合には作成しない。

air8

総合スコア5

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

1クリップ

投稿2020/02/15 16:06

VBA初心者です。
今は以下のような作業をしたいと思っています。

【作業】
ブックの中には
"入力"シート・・A1セルからA10セルには 10,20,30,40の数字をランダムに入力
"10"シート
”30”シート
上記3つのシートが存在します。

入力シートのA1セルからA10セルを確認して、その数字がないものについて
その数字をシートの名前にして、シートを新規に作成する。

結果としては”20”シートと”40”シートが新規に作成される。

【エラー】
実行時エラーとして
「既に名前が使用されています。別の名前を入力してください。」がでます。

【コード】
Sub Sheet作成()

Dim i
Dim s As Worksheet
Dim find_name As String
Dim flg As Boolean

For i = 1 To 10

find_name = Worksheets("入力").Cells(i, 1) flg = False For Each s In ThisWorkbook.Worksheets If s.Name <> find_name Then flg = True GoTo L1 End If Next

L1:

If flg = True Then Worksheets.Add after:=Worksheets(Worksheets.Count) Worksheets(Worksheets.Count).Name = Worksheets("入力").Cells(i, 1) End If

Next i
End Sub

どのようにしたらいいかまったくわかりません。
どなたか教えていただけないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

数値か文字列かについては、
Dim find_name As Stringと文字列として宣言しているので、
find_name = Worksheets("入力").Cells(i, 1)と代入したときに文字列に暗黙の型変換されるので問題ないです。

ロジックが間違っています。
全てのシート名とセルの値を比較して一つでも異なる名前があったらシートを新規作成するというロジックになっています。
そうではなくて、
全てのシート名とセルの値を比較して一つでも同じ名前があったらシートを新規作成しないというロジックにしないと。

呈示のコードを最小限の修正で済ますなら、

vba

1Sub Sheet作成() 2 Dim i As Long 3 Dim s As Worksheet 4 Dim find_name As String 5 Dim flg As Boolean 6 7 For i = 1 To 10 8 9 find_name = Worksheets("入力").Cells(i, 1) 10 11 flg = True 12 13 For Each s In ThisWorkbook.Worksheets 14 15 If s.Name = find_name Then 16 flg = False 17 Exit For 18 End If 19 Next 20 21 If flg = True Then 22 23 Worksheets.Add after:=Worksheets(Worksheets.Count) 24 Worksheets(Worksheets.Count).Name = Worksheets("入力").Cells(i, 1) 25 End If 26 27 Next i 28End Sub

別案

シートの存在チェックは他でも使えそうなので関数にします。
ループですべてのシート名をチェックしてもいいのですがシート数が多いと重くなりますので、例外処理で存在チェックします。(シートにアクセスしてエラーがでたら存在しない)

VBA

1Sub Sheet作成2() 2 Dim r As Range 3 For Each r In Worksheets("入力").Range("A1:A10") 4 If Not SheetExists(r.Text) Then 5 Worksheets.Add(after:=Worksheets(Worksheets.Count)).Name = r.Text 6 End If 7 Next 8End Sub 9 10'シートの存在チェック関数 11'指定した名前のシートが存在したらTrue、しなかったらFalseを返す 12Function SheetExists(SheetName As String) As Boolean 13 Dim ws As Worksheet 14 On Error Resume Next 15 Set ws = ThisWorkbook.Worksheets(SheetName) 16 On Error GoTo 0 17 SheetExists = Not (ws Is Nothing) 18End Function

投稿2020/02/15 18:46

編集2020/02/15 23:56
hatena19

総合スコア33699

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

air8

2020/02/16 00:17

回答ありがとうございます。 そもそものロジックの考え方が悪いことには気づかされました。 私のコードを生かしていただいたものを修正すると、エラーとして、また「既に名前が使用されています。別の名前を入力してください。」がでます。 入力シートの1行目には”20”が入っていて新規に”20”のシートが作成されますが、入力シートの2行目にも”20”が入っており、シートは作成されますが、エラーがでてシートの名前が変更されません。 別案の関数にして実行するパターンも試させていただきました。 すごい!感動しました。まだ自分で関数を定義するところまではいけていませんが、今後の参考にさせてください。
hatena19

2020/02/16 00:38

> エラーがでてシートの名前が変更されません。 当方のサンプルではエラーは出ません。コードを写し間違えてませんか。
guest

0

ベストアンサー

こんにちはこんばんは。よろしくおねがいいたします。
これ、私が思うに、A列には”数値”が入ってて、いっぽうシート名は”文字列”なので、
単純に比較することができなくて失敗しているのかな?と思いました。

そこでCStrで変換してから比較するようにしてみました。
(ちなみに、Str()では、正の数値を変換するとアタマに半角空白ができるそうです。なのでここではそれは使えないのでCStr()にしました)

そうして作ってみたのが、以下のとおりです。

VBA

1Option Explicit 2 3Sub InspectAndCreateNewSheet() 4'"入力"シートのA列を上から順にサーチして、 5'その値の名前と一致するシートがないとき、新規作成する 6 7Dim SearchSheet As Worksheet 8Set SearchSheet = ThisWorkbook.Worksheets("入力") 9 10Dim i As Long 11Dim r As Range 12Dim flag As Boolean 13 14SearchSheet.Select 15For Each r In Range("A1", Range("A1").End(xlDown)) 16flag = False 17 For i = 1 To Worksheets.Count 18 If Worksheets(i).Name = CStr(r.Value) Then 19 flag = True 20 End If 21 Next i 22 If flag = False Then 23 Worksheets.Add.Name = CStr(r.Value) 24 End If 25Next r 26End Sub 27

書きっぷりはちょっと変わりましたが、基本的にあなたの試みていることと同じです。

いかがでしょうか?

投稿2020/02/15 18:08

AkiSaito

総合スコア110

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

air8

2020/02/16 00:32

ご回答いただきありがとうございます。 実行してみたら私がやりたいと思っていた結果とおりになりました。 とてもわかりやすく、今後の考え方にも生かせそうです。 本当にありがとうございます。
guest

0

んと、

If flg = True Then

ここが、
あれば(True)何もしない
無ければ(False)新規シート挿入
なので、

If flg = false Then

ですかね。。。。

僕ならこう書くかな。。。

ExcelVBA

1Sub Sheet作成() 2 Dim i 3 Dim s As Worksheet 4 Dim find_name As String 5 6 For i = 1 To 10 7 find_name = Worksheets("入力").Cells(i, 1) 8 For Each s In ThisWorkbook.Worksheets 9 If s.Name <> find_name Then 10 Exit For 11 End If 12 Next 13 14 If s Is Nothing Then 15 Worksheets.Add after:=Worksheets(Worksheets.Count) 16 Worksheets(Worksheets.Count).Name = find_name 17 End If 18 Next i 19End Sub

もう少し真面目に考えたら、こうかな。
(ついでに並び順もリスト順に並べ替えしてみました^^;)

ExcelVBA

1Option Explicit 2 3Sub test() 4 Dim wsh As Worksheet 5 Dim rngList As Range 6 Dim c As Range 7 Dim sName As String 8 Dim ix As Long 9 10 Set rngList = Worksheets("入力").Range("A1:A10") 11 ix = 1 12 For Each c In rngList 13 sName = c.Value 14 If ChkName(sName) Then 15 On Error GoTo ErrHandler 16 Set wsh = Worksheets(sName) 17 On Error GoTo 0 18 If wsh.Index <> ix + 1 Then wsh.Move after:=Worksheets(ix) 19 ix = ix + 1 20 Else 21 sName = IIf(Len(sName), sName, "空白セル") 22 MsgBox c.Address(False, False) & ":" & sName & " NG! スキップします。" 23 End If 24 Next 25 26 Exit Sub 27 28ErrHandler: 29 With Worksheets 30 .Add(after:=.Item(ix)).Name = sName 31 End With 32 Resume 33End Sub 34 35Function ChkName(ByVal s As String) As Boolean 36 Dim v 37 38 Select Case Len(s) 39 Case 1 To 31 40 For Each v In Split(":,\,/,?,*,[,]", ",") 41 If InStr(s, v) Then Exit Function 42 Next 43 Case Else 44 Exit Function 45 End Select 46 ChkName = True 47End Function

参考になれば。
※バグがあるかも知れませんので自己責任で。
ちゃんとしようと思ったら何度見直してもきりがない><

投稿2020/02/16 01:35

mattuwan

総合スコア2136

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問