LoginSignup
0
1

More than 5 years have passed since last update.

C++ Builder 10.2 Tokyo > JSON > 複数のValueを置換する | 問題点 > 意図しない置換 (連鎖的な失敗)

Last updated at Posted at 2019-05-21
動作環境
RAD Studio 10.2 Tokyo Update 3

処理概要

  • JSONオブジェクトのValueを置換したい
    • 用途: 変換元と変換先の文字列が渡されたとき、それに基づきJSONの中身を書換える

方針

  • ToString()した文字列に対して置換をする
  • その結果をJSONオブジェクトとして戻す

実装

Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE で管理されるコンポーネント
    TButton *Button1;
    TMemo *Memo1;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall FormCreate(TObject *Sender);
private:    // ユーザー宣言
    TJSONObject * __fastcall JSON_replaceStrings(TJSONObject *srcPtr, String fromStr, String toStr);
public:     // ユーザー宣言
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DBXJSON.hpp>
#include <memory>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TJSONObject *asrc, *adst;

    asrc = new TJSONObject();

    asrc->AddPair(L"name", L"John Smith");
    asrc->AddPair(L"age", L"33");
    asrc->AddPair(L"place", L"Sydney");
    Memo1->Lines->Add(asrc->ToString());

    String fromstr = "John Smith,33";
    String tostr = "7of9,79";

    adst = JSON_replaceStrings(asrc, fromstr, tostr);

    if (adst != NULL) {
        Memo1->Lines->Add(adst->ToString());
    }

    delete asrc;
    delete adst;
}

TJSONObject * __fastcall TForm1::JSON_replaceStrings(TJSONObject *srcPtr, String fromStr, String toStr)
{
    // 1. parse csv string
    std::unique_ptr<TStringList> fromSL(new TStringList);
    fromSL->StrictDelimiter = true;
    fromSL->DelimitedText = ',';
    fromSL->DelimitedText = fromStr;
    std::unique_ptr<TStringList> toSL(new TStringList);
    toSL->StrictDelimiter = true;
    toSL->DelimitedText = ',';
    toSL->DelimitedText = toStr;

    if (fromSL->Count != toSL->Count) {
        return NULL;  // error
    }

    // 2. replace values
    String replaced = srcPtr->ToString();
    for(int idx=0; idx<fromSL->Count; idx++) {
        String afrom = fromSL->Strings[idx];
        String ato = toSL->Strings[idx];
        replaced = StringReplace(replaced, afrom, ato, TReplaceFlags()<<rfReplaceAll);
    }

    return dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(replaced));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    Memo1->Lines->Clear();
}
//---------------------------------------------------------------------------

実行例

2019-05-21_14h30_45.png

問題点

意図しない置換 (連鎖的な失敗)

(1,2,3,4,5)のようなValueを持つ5つのKeyを持つJSONオブジェクトがあるとする。

(2,3,4,5,6)に置換するとき、StringReplace()を逐次実施すると'(6,6,6,6,6)`になってしまう場合がある。

  1. (1,2,3,4,5)
  2. (2,2,3,4,5)
  3. (3,3,3,4,5)
  4. (4,4,4,4,5)
  5. (5,5,5,5,5)
  6. (6,6,6,6,6)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1