QA@IT
この質問・回答は、@ITの旧掲示板からインポートされたものです。

正規表現でダブルクォーテーション囲み&カンマ区切りを表現したい

こんにちは。
VB.NETでプログラミングしています。
自作クラスのプロパティ値(string)に複数の値(複数の文字列)をセットしたく、正規表現でダブルクォーテーション囲み&カンマ区切りを表現したいのですが、なかなか上手くいきません。
(プロパティ値をどうしても1つの文字列として扱いたく、複数の文字列のシリアル化を考えたのですが、バイナリ等になるとメンテナンスが大変になるので、正規表現に走りました。)

[正規表現で表したいこと]
・1つの文字列はダブルクォーテーションで囲む
・複数個の文字列はカンマで区切る(カンマで終了してはいけない)
・ヌル、スペース、タブは文字列として許さない
・正規表現をクリアした場合は、ダブルクォーテーションを含まない文字列をキャプチャしたい

例.

OK:
"abc" → abcをキャプチャ
"abc","def","ghi" → abcとdefとghiをキャプチャ
"ab"c","d,ef" → ab"cとd,efをキャプチャ

NG:
"abc",
""
" "
"","abc"

勉強不足で恐縮ですが、ご教授の程よろしくお願い致します。

質問者:EOSB200

回答

 私も色々考えたのですが...外部からは与えられない、と考えていいのでしょうか?外部から、「abc,"aa""bb""cc",cde」(abc aa"bb"cc cde)と与えられたら、どうなるのでしょう?
 そういうことを考えると、「"""csv"",""in"",""csv"""」なんてことをやられると、とっても面倒なんですよね
 先読みか、後戻りが必要なので、正規表現でするのは、ちょっと苦しいかと。。。

[ メッセージ編集済み 編集者: Jitta 編集日時 2004-07-12 08:51 ]

項目数が決まっているなら、
^".+",(".+",){}".+"$
で、検査はできると思います。取り出しは、CaptureCollectionクラスかなぁ?
[ メッセージ編集済み 編集者: Jitta 編集日時 2004-07-12 12:13 ]

投稿者:Jitta

編集 履歴 (0)

ども、ほむらです。

いわゆるエクセルで出力するようなK3形式のCVSを分解できればよいのですよね?
以前にもどこかで出した記憶があるのですがperlだとできるのでJavaや.NETみたいな
正規表現を持っているものであればできると思いますよ。
最悪個人ユースであればpcre.dllを利用してみるとか

ポイントは最短マッチと最長マッチの組み合わせです。
"が続かない最長マッチ
または"を含まない,までの最短マッチ

# とりあえず列の取り出し;
my @result = ($work =~ m/((?:\".?[^\"]\")[ \t]|(?:.*?))\,/sg);
# /sgは .に改行を含めてGlobal検索を有効にするということです。
# /s がない場合には(?:.|\r\n)で代用できるはず。
# @result は列を保存するための一元配列です

くわしくはこちらをどうぞ。
http://www.google.co.jp/search?q=site%3Awww.atmarkit.co.jp+%E3%81%BB%E3%82%80%E3%82%89%E3%81%A7%E3%81%99%E3%80%82+perl+CSV&ie=UTF-8&hl=ja&btnG=Google+%E6%A4%9C%E7%B4%A2&lr=lang_ja

投稿者:ほむら

編集 履歴 (0)

ども、ほむらです。

.NETのところで何度もPerlの話をするのも気が引けたので
勉強がてらVB.NETで作ってみました。
初めてのプログラムなので変な記述になっている部分が多いかと思います。

分解してArrayListに追加する部分でデータの整合性チェックなどをしているのですが
この部分でバグがあるらしく、""というデータでエラーになってくれません。
あくまで参考程度にどぞ。

追伸:
変なところとか、改善点はどんどん指摘してもらえるとうれしいです。

#BBコード記述ミスを修正



Makefile
\---------
LIBSOPT=/r:System.dll /r:Mscorlib.dll
OPT=/optimize+ /debug- /nologo /optionexplicit+ /optionstrict+

ALL: csvtest.vb
    vbc.exe $(OPT) $(LIBSOPT) csvtest.vb

\---------
csvtest.vb
\---------------
Option Strict On
Option Explicit On

Imports System
Imports System.Text.RegularExpressions
Imports System.Collections

Class Application
  Public Shared Sub Main( argv() as String )
    Dim DATA As String = "abc,,""rr""""r""""r"",ty,"""",yyu,"""""",lll"
    Dim rePATTERN As String = "^(((?:"".*?[^""]"")[ \t]*|(?:.*?)),)+"

    Dim rows as ArrayList
    rows = RecordSplit(DATA, rePATTERN)
    Display(rows)
  End Sub

  ' すべての列データを表示
  Public Shared Sub Display(Rows as ArrayList)
    Dim wkRI as Integer
    For wkRI = 0 To Rows.Count -1
      Console.Writeline(wkRI & ":" & Rows(wkRI).ToString())
    Next wkRI
  End Sub

  ' 1件のレコードを列に分解してArrayListに格納する
  Public Shared Function RecordSplit(DATA as String, rePATTERN as String) As ArrayList
    Dim m as Match
    Dim cc as CaptureCollection
    Dim matches as MatchCollection
    Dim result as New ArrayList()

    ' 正規表現にマッチさせるために最後,を追加
    matches = Regex.Matches( DATA & ",", rePATTERN, RegexOptions.Singleline)
    IF matches.Count = 0  Then
      Console.WriteLine("マッチしませんでした")
      return result
    End if

    Dim wkGI as Integer = 0
    Dim wkCI as Integer = 0
    Dim szMatch As String

    m = matches.item(0)
    wkGI = m.Groups.Count -1
    While m.Groups( wkGI ).Value <> ""
      cc = m.Groups(wkGI).Captures
      For wkCI=0 To cc.Count - 1
        ' マッチしたデータの修正
        szMatch = cc(wkCI).ToString()
        if szMatch = "" then
          Console.WriteLine("DATA Error(" & wkCI & "):" & """" & szMatch &"""")
        end if
        If szMatch.indexOf("""") <> -1 then
          ' クォーテーション削除
          szMatch = szMatch.Substring(1,szMatch.length - 2 )
          ' 二重引用符を一つに
          szMatch = szMatch.Replace("""""","""")
        end if
        result.Add( szMatch )
      Next wkCI
      wkGI = wkGI + 1
    End While
    return result
  End Function
End Class

[ メッセージ編集済み 編集者: ほむら 編集日時 2004-07-12 15:38 ]

投稿者:ほむら

編集 履歴 (0)

Jittaさん、ほむらさん、ご返答ありがとうございます。
早急にご返答頂いたのですが、なにせ正規表現(VB.NETも)初心者なもので、ご返答頂いた内容を理解して自分のものにするのに少々時間がかかりそうです。(なさけない・・・)
まずはお礼まで。

投稿者:EOSB200

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。