2012-03-29

Force.com : Apex で文字列に含まれる半角カタカナを全角カタカナに置換したい


Apex で文字列に含まれる半角カタカナを全角カタカナに置換したい



したくない!
所詮は、置換したい文字の対応 Map を作成してそれで置換しているに過ぎない :-)。



○ 文字列に含まれる半角カタカナを全角カタカナに置換したい

  • 半角カタカナの範囲は「FF61-FF9F」とする
  • 該当する濁点を含む文字が存在しない場合は[全角カタカナ + 全角濁点]とする
  • 該当する半濁点を含む文字が存在しない場合は[全角カタカナ + 全角半濁点]とする
■ 実装クラス
public class StringUtility {

    /** インスタンス */
    private static final StringUtility instance = new StringUtility();

    /** 16 進数表記 → 10 進数表記置換 Map */
    private Map<String, Integer> hexadecimalToDecimalMap;

    /** 半角カナ・置換 Map */
    private Map<String, String> replaceMap;
    /** 半角カナ・置換 Map Unicode */
    private Map<String, String> replaceHexadecimalMap;

    /** 濁点・置換 Map */
    private Map<String, String> replaceDakutenMap;
    /** 濁点・置換 Map Unicode */
    private Map<String, String> replaceDakutenHexadecimalMap;

    /** 半濁点・置換 Map */
    private Map<String, String> replaceHandakutenMap;
    /** 半濁点・置換 Map Unicode */
    private Map<String, String> replaceHandakutenHexadecimalMap;

    /**
     * コンストラクタ
     */
    private StringUtility() {

        // 16 進数表記 → 10 進数表記置換 Map 作成
        hexadecimalToDecimalMap = new Map<String, Integer>();
        hexadecimalToDecimalMap.put('0', 0);
        hexadecimalToDecimalMap.put('1', 1);
        hexadecimalToDecimalMap.put('2', 2);
        hexadecimalToDecimalMap.put('3', 3);
        hexadecimalToDecimalMap.put('4', 4);
        hexadecimalToDecimalMap.put('5', 5);
        hexadecimalToDecimalMap.put('6', 6);
        hexadecimalToDecimalMap.put('7', 7);
        hexadecimalToDecimalMap.put('8', 8);
        hexadecimalToDecimalMap.put('9', 9);
        hexadecimalToDecimalMap.put('A', 10);
        hexadecimalToDecimalMap.put('B', 11);
        hexadecimalToDecimalMap.put('C', 12);
        hexadecimalToDecimalMap.put('D', 13);
        hexadecimalToDecimalMap.put('E', 14);
        hexadecimalToDecimalMap.put('F', 15);

        // 半濁点・置換 Map 作成
        replaceHandakutenHexadecimalMap = new Map<String, String>();
        replaceHandakutenHexadecimalMap.put('FF8A,FF9F', '30D1');    // パ
        replaceHandakutenHexadecimalMap.put('FF8B,FF9F', '30D4');
        replaceHandakutenHexadecimalMap.put('FF8C,FF9F', '30D7');
        replaceHandakutenHexadecimalMap.put('FF8D,FF9F', '30DA');
        replaceHandakutenHexadecimalMap.put('FF8E,FF9F', '30DD');
        replaceHandakutenMap = new Map<String, String>();
        for(String key : replaceHandakutenHexadecimalMap.keySet()) {
            replaceHandakutenMap.put(unicodeToString(key.split(',', 0)), unicodeToString(replaceHandakutenHexadecimalMap.get(key).split(',', 0)));
        }

        // 濁点・置換 Map 作成
        replaceDakutenHexadecimalMap = new Map<String, String>();
        replaceDakutenHexadecimalMap.put('FF76,FF9E', '30AC');    // ガ
        replaceDakutenHexadecimalMap.put('FF77,FF9E', '30AE');
        replaceDakutenHexadecimalMap.put('FF78,FF9E', '30B0');
        replaceDakutenHexadecimalMap.put('FF79,FF9E', '30B2');
        replaceDakutenHexadecimalMap.put('FF7A,FF9E', '30B4');
        replaceDakutenHexadecimalMap.put('FF7B,FF9E', '30B6');    // ザ
        replaceDakutenHexadecimalMap.put('FF7C,FF9E', '30B8');
        replaceDakutenHexadecimalMap.put('FF7D,FF9E', '30BA');
        replaceDakutenHexadecimalMap.put('FF7E,FF9E', '30BC');
        replaceDakutenHexadecimalMap.put('FF7F,FF9E', '30BE');
        replaceDakutenHexadecimalMap.put('FF80,FF9E', '30C0');    // ダ
        replaceDakutenHexadecimalMap.put('FF81,FF9E', '30C2');
        replaceDakutenHexadecimalMap.put('FF82,FF9E', '30C5');
        replaceDakutenHexadecimalMap.put('FF83,FF9E', '30C7');
        replaceDakutenHexadecimalMap.put('FF84,FF9E', '30C9');
        replaceDakutenHexadecimalMap.put('FF8A,FF9E', '30D0');    // バ
        replaceDakutenHexadecimalMap.put('FF8B,FF9E', '30D4');
        replaceDakutenHexadecimalMap.put('FF8C,FF9E', '30D6');
        replaceDakutenHexadecimalMap.put('FF8D,FF9E', '30D9');
        replaceDakutenHexadecimalMap.put('FF8E,FF9E', '30DC');
        replaceDakutenHexadecimalMap.put('FF73,FF9E', '30F4');    // ヴ
        replaceDakutenMap = new Map<String, String>();
        for(String key : replaceDakutenHexadecimalMap.keySet()) {
            replaceDakutenMap.put(unicodeToString(key.split(',', 0)), unicodeToString(replaceDakutenHexadecimalMap.get(key).split(',', 0)));
        }

        // 半角カナ・置換 Map 作成
        replaceHexadecimalMap = new Map<String, String>();
        replaceHexadecimalMap.put('FF61', '3002');    // Halfwidth CJK punctuation
        replaceHexadecimalMap.put('FF62', '300C');
        replaceHexadecimalMap.put('FF63', '300D');
        replaceHexadecimalMap.put('FF64', '3001');
        replaceHexadecimalMap.put('FF65', '30FB');    // Halfwidth Katakana variants
        replaceHexadecimalMap.put('FF66', '30F2');
        replaceHexadecimalMap.put('FF67', '30A1');
        replaceHexadecimalMap.put('FF68', '30A3');
        replaceHexadecimalMap.put('FF69', '30A5');
        replaceHexadecimalMap.put('FF6A', '30A7');
        replaceHexadecimalMap.put('FF6B', '30A9');
        replaceHexadecimalMap.put('FF6C', '30E3');
        replaceHexadecimalMap.put('FF6D', '30E5');
        replaceHexadecimalMap.put('FF6E', '30E7');
        replaceHexadecimalMap.put('FF6F', '30C3');
        replaceHexadecimalMap.put('FF70', '30FC');
        replaceHexadecimalMap.put('FF71', '30A2');
        replaceHexadecimalMap.put('FF72', '30A4');
        replaceHexadecimalMap.put('FF73', '30A6');
        replaceHexadecimalMap.put('FF74', '30A8');
        replaceHexadecimalMap.put('FF75', '30AA');
        replaceHexadecimalMap.put('FF76', '30AB');
        replaceHexadecimalMap.put('FF77', '30AD');
        replaceHexadecimalMap.put('FF78', '30AF');
        replaceHexadecimalMap.put('FF79', '30B1');
        replaceHexadecimalMap.put('FF7A', '30B3');
        replaceHexadecimalMap.put('FF7B', '30B5');
        replaceHexadecimalMap.put('FF7C', '30B7');
        replaceHexadecimalMap.put('FF7D', '30B9');
        replaceHexadecimalMap.put('FF7E', '30BB');
        replaceHexadecimalMap.put('FF7F', '30BD');
        replaceHexadecimalMap.put('FF80', '30BF');
        replaceHexadecimalMap.put('FF81', '30C1');
        replaceHexadecimalMap.put('FF82', '30C4');
        replaceHexadecimalMap.put('FF83', '30C6');
        replaceHexadecimalMap.put('FF84', '30C8');
        replaceHexadecimalMap.put('FF85', '30CA');
        replaceHexadecimalMap.put('FF86', '30CB');
        replaceHexadecimalMap.put('FF87', '30CC');
        replaceHexadecimalMap.put('FF88', '30CD');
        replaceHexadecimalMap.put('FF89', '30CE');
        replaceHexadecimalMap.put('FF8A', '30CF');
        replaceHexadecimalMap.put('FF8B', '30D2');
        replaceHexadecimalMap.put('FF8C', '30D5');
        replaceHexadecimalMap.put('FF8D', '30D8');
        replaceHexadecimalMap.put('FF8E', '30DB');
        replaceHexadecimalMap.put('FF8F', '30DE');
        replaceHexadecimalMap.put('FF90', '30DF');
        replaceHexadecimalMap.put('FF91', '30E0');
        replaceHexadecimalMap.put('FF92', '30E1');
        replaceHexadecimalMap.put('FF93', '30E2');
        replaceHexadecimalMap.put('FF94', '30E4');
        replaceHexadecimalMap.put('FF95', '30E6');
        replaceHexadecimalMap.put('FF96', '30E8');
        replaceHexadecimalMap.put('FF97', '30E9');
        replaceHexadecimalMap.put('FF98', '30EA');
        replaceHexadecimalMap.put('FF99', '30EB');
        replaceHexadecimalMap.put('FF9A', '30EC');
        replaceHexadecimalMap.put('FF9B', '30ED');
        replaceHexadecimalMap.put('FF9C', '30EF');
        replaceHexadecimalMap.put('FF9D', '30F3');
        replaceHexadecimalMap.put('FF9E', '309B');
        replaceHexadecimalMap.put('FF9F', '309C');
        replaceMap = new Map<String, String>();
        for(String key : replaceHexadecimalMap.keySet()) {
            replaceMap.put(unicodeToString(key.split(',', 0)), unicodeToString(replaceHexadecimalMap.get(key).split(',', 0)));
        }
    }

    /**
     * Unicode を文字列に変換する
     * @param unicodes unicode 配列
     * @return 文字列
     */
    public String unicodeToString(String[] unicodes) {
        List<Integer> chars = new List<Integer>();
        for(String unicode : unicodes) {
            Integer c = 0;
            for(Double i=0, len=unicode.length(); i<len; i++) {
                c += (Math.pow(16, (len - i - 1)).intValue() * hexadecimalToDecimalMap.get(unicode.substring(i.intValue(), i.intValue()+1)));
            }
            chars.add(c);
        }
        return String.fromCharArray(chars);
    }

    /**
     * 置換が必要か判定する
     * ※ 半角カナ(FF61-FF9F)が含まれている場合置換を必要とする
     * @param s 文字列
     * @return true: 必要/false: 不必要
     */
    public Boolean isReplace(String s) {
        return !Pattern.matches('^[^\\uFF61-\\uFF9F]{1,}$', s);
    }

    /**
     * 置換
     * @param s 文字列
     * @return 置換文字列
     */
    public String replace(String s) {
        if(s == null || s == '') return s;

        // 半濁点
        if(!isReplace(s)) return s;
        for(String key : replaceHandakutenMap.keySet()) {
            s = s.replaceAll(key, replaceHandakutenMap.get(key));
        }

        // 濁点
        if(!isReplace(s)) return s;
        for(String key : replaceDakutenMap.keySet()) {
            s = s.replaceAll(key, replaceDakutenMap.get(key));
        }

        // 半角カナ
        if(!isReplace(s)) return s;
        for(String key : replaceMap.keySet()) {
            s = s.replaceAll(key, replaceMap.get(key));
        }

        return s;
    }

    /**
     * インスタンス取得
     * @return インスタンス
     */
    public static StringUtility getInstance() {
        return StringUtility.instance;
    }
}

■ 実行
// インスタンス取得
StringUtility sutility = StringUtility.getInstance();

// 置換する文字列作成(半角「パガア」)
String[] codes = new String[]{'FF8A','FF9F', 'FF76', 'FF9E', 'FF71'};
String str = sutility.unicodeToString(codes);

// 置換
String restr = sutility.replace(str);



◆ メモ

  • Apex クラスは UTF-8
  • Apex クラスで半角カタカナを記述しないが吉、ぽい
  • 置換 Map を修正した場合は isReplace() メソッドの修正も忘れないこと



◇ 環境

  • Salesforce - Developer Edition - API バージョン 24.0



◇ 関連記事


文字コード : Unicode


◆ Unicode


2012-03-28

Force.com : Apex で Unicode を文字列に変換したい


Apex で Unicode(\u0000)を文字列に変換したい



○ Unicode(\u0000)を文字列に変換したい

/**
 * Unicode を文字列に変換する
 * @param hexadecimal Unicode
 * @return 文字列
 */
static String unicodeToString(String unicode) {
    Map<String, Integer> hexadecimalToDecimalMap = new Map<String, Integer>();
    hexadecimalToDecimalMap.put('0', 0);
    hexadecimalToDecimalMap.put('1', 1);
    hexadecimalToDecimalMap.put('2', 2);
    hexadecimalToDecimalMap.put('3', 3);
    hexadecimalToDecimalMap.put('4', 4);
    hexadecimalToDecimalMap.put('5', 5);
    hexadecimalToDecimalMap.put('6', 6);
    hexadecimalToDecimalMap.put('7', 7);
    hexadecimalToDecimalMap.put('8', 8);
    hexadecimalToDecimalMap.put('9', 9);
    hexadecimalToDecimalMap.put('A', 10);
    hexadecimalToDecimalMap.put('B', 11);
    hexadecimalToDecimalMap.put('C', 12);
    hexadecimalToDecimalMap.put('D', 13);
    hexadecimalToDecimalMap.put('E', 14);
    hexadecimalToDecimalMap.put('F', 15);

    Integer c = 0;
    for(Double i=2, len=unicode.length(); i<len; i++) {
        c += (Math.pow(16, (len - i - 1)).intValue() * hexadecimalToDecimalMap.get(unicode.substring(i.intValue(), i.intValue()+1)));
    }
    List<Integer> chars = new List<Integer>();
    chars.add(c);
    return String.fromCharArray(chars);
}



◆ メモ




◇ 環境

  • Salesforce - Developer Edition - API バージョン 24.0



◇ 参考


Force.com : Apex で文字列が byte 数以下か判定したい


Apex で文字列が byte 数以下か判定したい



そもそも salesforce 内でシステムが完了していたら byte 数など気にする必要は、よほどのことがない限りないだろうと思う。



○ 文字列が byte 数以下か判定したい

/**
 * Byte 数以下か判定を行う
 * @param bytes byte 数
 * @param s 文字列
 * @return true: 以下/false: より上
 */
static Boolean isByteLessThan(Integer bytes, String s) {
    if(bytes < 0) return false;
    if(s == null || s == '') return true;

    Integer zenkakuLength = s.replaceAll('[\\uFF61-\\uFF9F\\u0020-\\u007E]', '').length();
    Integer hankakuLength = s.length() - zenkakuLength;
    return bytes >= zenkakuLength * 2 + hankakuLength;
}



◆ メモ

  • 文字列は長さしか取得できない
  • force.com 上で Apex コードは UTF-8 で処理されているらしいので、半角文字のコードは Unicode (半角カタカナをハードコーディングしたらシステムエラーが発生した)
  • 正規表現は Pattern (Java 2 Platform SE 5.0) を参照



◇ 環境

  • Salesforce - Developer Edition - API バージョン 24.0



◇ 参考


2012-03-14

Windows バッチファイル : テキストファイルにある文字列を置換したい


Windows バッチファイルでテキストファイルにある文字列を置換したい
  • sample_input.txt に「"foo"」という文字列(「"」も文字列)が出現したら「"boo"」という文字列に置換する
  • sample_output.txt に出力する (既にファイルが存在する場合は上書きする)



○ テキストファイルにある「"foo"」という文字列を「"boo"」という文字列に置換したい

■ ローカル変数版
@echo off

set ofilename=sample_output.txt

type nul >%ofilename%

setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%A in (sample_input.txt) do (
    set line=%%A
    echo !line:"foo"="boo"!>>%ofilename%
)
endlocal

■ ラベル版
@echo off

set ofilename=sample_output.txt

type nul >%ofilename%

for /f "delims=" %%A in (sample_input.txt) do (
    set line=%%A
    call :REPLACE
)

GOTO :END

:REPLACE
    echo %line:"foo"="boo"%>>%ofilename%

:END



◇ 環境

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

2012-03-10

Force.com : Apex で公開グループを削除したい


やっぱり、 Apex で公開グループを作成したら
Apex で公開グループを削除したい



○ 公開グループを削除したい


■ Trigger (API version 12.0)
trigger AccountTrigger on Account (after insert, after delete) {
    if(Trigger.isInsert) {
        
        Account[] accounts = Trigger.new;
    
        List<Group> groups = new List<Group>();
        for(Account account : accounts) {
            Group g = new Group();
            g.Type = 'Regular';                    // タイプ:公開グループ
            g.Name = account.Name;                 // グループ名
            groups.add(g);
        }
        insert groups;

    } else if(Trigger.isDelete) {

        Account[] accounts = Trigger.old;

        // ※ 公開グループでレコードの共有を行っている場合は、その共有を削除する必要がある ※

        Set<String> names= new Set<String>();
        for(Account account : accounts) {
            names.add(account.Name);
        }
        List<Group> groups = [SELECT Id FROM Group WHERE Name IN : names];
        if(groups.size() > 0) {
            delete groups;
        }

    }
}
※ Group の delete は API Version 12.0 以前で可能 ... ぽい!?
※ 公開グループでレコードの共有を行っている場合は、その共有を削除する必要がある
※ 公開グループにメンバーが存在しても関係なし(多分、主従関係なんだろう@適当)



◆ メモ

で Group の delete に関する記述が違う気がする ...

「Apex で公開グループを削除したい」なんで思わないが吉!



◇ 環境

  • Salesforce - Developer Edition - API バージョン 24.0



◇ 参考


Force.com : Apex で公開グループを作成したい


Apex で公開グループを作成したい



○ 公開グループを作成したい

  • 取引先(Account)作成の際に、公開グループは下記の通り作成する
    • グループ名: 取引先名
    • API 参照名: 'g_' + 取引先ID

■ Trigger (API version 24.0)
trigger AccountTrigger on Account (after insert) {
    Account[] accounts = Trigger.new;

    List<Group> groups = new List<Group>();
    for(Account account : accounts) {
        Group g = new Group();
        g.Type = 'Regular';                    // タイプ:公開グループ
        g.Name = account.Name;                 // グループ名
        g.DeveloperName = 'g_' + account.Id;   // API 参照名
        groups.add(g);
    }
    insert groups;
}
※ Group#DeveloperName は API version 24.0 以降より可能



○ 公開グループを作成し、メンバーに追加したい

  • メンバーは追加した取引先の所有者とする

■ Trigger (API version 24.0)
trigger AccountTrigger on Account (after insert) {
    Account[] accounts = Trigger.new;

    // Group 作成
    List<Group> groups = new List<Group>();
    for(Account account : accounts) {
        Group g = new Group();
        g.Type = 'Regular';                    // タイプ:公開グループ
        g.Name = account.Name;                 // グループ名
        g.DeveloperName = 'g_' + account.Id;   // API 参照名
        groups.add(g);
    }
    insert groups;

    // GroupMember 作成
    List<GroupMember> members = new List<GroupMember>();
    for(Account account : accounts) {
        GroupMember member = new GroupMember();
        for(Group g : groups){
            if(g.Name == account.Name) {
                member.GroupId = g.Id;
                break ;
            }
        }
        member.UserOrGroupId = account.OwnerId;
        members.add(member);
    }
    GroupMemberOperations.insertGroupMember(members);

}

■ ApexClass (API version 14.0)
public class GroupMemberOperations {

    public static void insertGroupMember(GroupMember member) {
        insert member;
    }

    public static void insertGroupMember(List<GroupMembe> members) {
        insert members;
    }

}
※ GroupMember の DML 操作は insert/update に限り、API Version 14.0 以前で可能



◇ 環境

  • Salesforce - Developer Edition - API バージョン 24.0



◇ 参考


2012-03-08

Force.com : sObject#clone()


sObject clone(Boolean opt_preserve_id
                     , Boolean opt_IsDeepClone
                     , Boolean opt_preserve_readonly_timestamps
                     , Boolean opt_preserve_autonumber)



○ パラメータ

  • opt_preserve_id
    • true: ID を引き継ぐ
    • false: ID はクリアされる
  • opt_IsDeepClone
    • true: 深いコピー(クローン化されたオブジェクトに変更を加えても元のオブジェクトに影響しない)
    • false: 浅いコピー
  • opt_preserve_readonly_timestamps
    • true: CreatedById, CreatedDate, LastModifiedById, LastModifiedDate を引き継ぐ
    • false: CreatedById, CreatedDate, LastModifiedById, LastModifiedDate はクリアされる
  • opt_preserve_autonumber
    • true: 自動採番を引き継ぐ
    • false: 自動採番はクリアされる



○ 例

※ シチュエーションはフィーリングで
  • Visualforce で[取引先]と[取引先責任者]をともに新規登録する画面を作成するとか
  • その際、[取引先責任者]を登録時に入力規則、Trigger 等でエラーが発生する可能性があるとか
  • エラー発生時は、元の画面に戻って再入力を促すとか
  • ※ この場合[取引先]はロールバックされ、insert はなかったことにされるのだけれども、オブジェクトには登録後に設定された ID がそのまま設定されたままになるのです
public Account account {get; set;}
public List<Contact> contacts {get; set}

public PageReference save() {

    Savepoint sp = Database.setSavepoint();

    try {
        insert account;
    } catch(DmlException e) {
        for(Integer i=0; i<e.getNumDml(); i++) {
            if(StatusCode.FIELD_CUSTOM_VALIDATION_EXCEPTION == e.getDmlType(i)) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, e.getDmlMessage(i), ''));
            }
        }
        Database.rollback(sp);
           return null;
    }

    for(Contact contact : contacts) {
        contact.accountid = account.Id;
    }
    try {
        insert contacts;
    } catch(DmlException e) {
        for(Integer i=0; i<e.getNumDml(); i++) {
            if(StatusCode.FIELD_CUSTOM_VALIDATION_EXCEPTION == e.getDmlType(i)) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, e.getDmlMessage(i), ''));
            }
        }
        account = account.clone(false, true, true, true);        // <<- ココ
        Database.rollback(sp);
        return null;
    }

    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'OK', ''));

    return null;
}



◇ 環境

  • Salesforce - Enterprise Edition - API バージョン 24.0



◇ 参考


2012-03-07

Windows バッチファイル : 二重ループの内側のループを抜けたい


Windows バッチファイルで二重ループの内側のループを抜けたい
  • csv ファイルを読み込む
  • コンソールに出力する
  • 一項目一行に表示する
  • 項目に特定の文字(「foo」)が出現したら、同行のそれ以降の項目は表示しない



○ CSV ファイルを読み込んでいる際に、特定の文字が出現したら同行のそれ以降の項目は表示しない

@echo off

setlocal ENABLEDELAYEDEXPANSION
FOR /F "delims=" %%A IN (sample.csv) DO (
    set x=0
    FOR %%a IN (%%A) DO (
        IF %%a EQU "foo" (
            set x=1
        )
        IF "!x!" EQU "0" (
            echo %%a
        )
    )
)
endlocal
単にフラグ立てて、処理を回避しているだけ。



◇ 環境

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

Windows バッチファイル : 任意の項目数の CSV ファイルの内容を読み込みたい


Windows バッチファイルで任意の項目数の CSV ファイルの内容を読み込みたい。
  • csv ファイルを読み込む
  • コンソールに出力する
  • 一項目一行に表示する



以前、 にてファイルの内容を読み込んでみたけど、for 文は 26 個までのトークンしか指定できない(help for)ぽいので他にないか探してみた。



○ CSV ファイルの内容を読み込みたい

@echo off

FOR /F "delims=" %%A IN (sample.csv) DO (
    echo +line: %%A
    FOR %%a IN (%%A) DO (
        echo -item: %%a
    )
)

Ex. カンマ区切り
■ sample.csv
"a","b","c","d","e"
"あ","い","う","え","お"
■ 実行結果
C:\>sample.bat
+line: "a","b","c","d","e"
-item: "a"
-item: "b"
-item: "c"
-item: "d"
-item: "e"
+line: "あ","い","う","え","お"
-item: "あ"
-item: "い"
-item: "う"
-item: "え"
-item: "お"
※ ダブルクォートつきの文字が %%a に設定されるぽい

Ex. タブ区切り
■ sample.csv
"a" "b" "c" "d" "e"
"あ" "い" "う" "え" "お"
■ 実行結果
C:\>sample.bat
+line: "a" "b" "c" "d" "e"
-item: "a"
-item: "b"
-item: "c"
-item: "d"
-item: "e"
+line: "あ" "い" "う" "え" "お"
-item: "あ"
-item: "い"
-item: "う"
-item: "え"
-item: "お"
※ ダブルクォートつきの文字が %%a に設定されるぽい



◇ 環境

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.