001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.util; 017 018import java.util.Iterator; 019import java.util.Map; 020import java.util.HashMap; 021import java.util.NoSuchElementException; // 8.5.5.1 (2024/02/29) spotbugs IT_NO_SUCH_ELEMENT 022 023import org.opengion.fukurou.system.HybsConst; 024 025/** 026 * JSONScan.java ã¯ã€JSONã§è¡Œã†ãŸã‚ã®Utilクラスã§ã™ã€‚ 027 * 028 * @og.rev 8.0.2.0 (2021/11/30) æ–°è¦ä½œæˆ 029 * @og.group ユーティリティ 030 * 031 * @version 8.0 032 * @author LEE. 033 * @since JDK17.0, 034 */ 035public final class JSONScan implements Iterator<String> { 036 /** システムã®æ”¹è¡Œã‚³ãƒ¼ãƒ‰ */ 037 private static final String CR = HybsConst.CR; 038 /** StringBilderãªã©ã®åˆæœŸå€¤ */ 039 private static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE; 040 041 /** 8.1.1.0 (2022/02/04) 大括弧([])ã¨åˆ¶å¾¡æ–‡å—(改行ç‰)も削除対象ã«ã—ã¾ã™ã€‚ */ 042 // 8.5.4.2 (2024/01/12) PMD 7.0.0 FieldDeclarationsShouldBeAtStartOfClass 043 private static final String JSON_TRIM = "\"{}[] "; 044 045 /** 処ç†å¯¾è±¡ã®æ–‡å—列 */ 046 private final String orgStr; 047 /** é–‹å§‹æ–‡å— */ 048 private final char stCh; 049 /** çµ‚äº†æ–‡å— */ 050 private final char edCh; 051 /** 検索範囲ã®é–‹å§‹ä½ç½® */ 052 private final int stScan; 053 /** 検索範囲ã®çµ‚了ä½ç½® */ 054 private final int edScan; 055 /** 処ç†é€”ä¸ã®åˆ‡ã‚Šå‡ºã—開始ä½ç½® */ 056 private int stAdrs; 057 /** 処ç†é€”ä¸ã®åˆ‡ã‚Šå‡ºã—終了ä½ç½® */ 058 private int edAdrs; 059 060 /** 061 * コンストラクタ 062 * 処ç†å¯¾è±¡ã®æ–‡å—列を解æžã™ã‚‹ JSONScan ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’作æˆã—ã¾ã™ã€‚ 063 * 検索範囲ã®é–‹å§‹ä½ç½®ã¯ã€ã‚¼ãƒ(0) ã§åˆæœŸåŒ–ã•ã‚Œã¾ã™ã€‚ 064 * 検索範囲ã®çµ‚了ä½ç½®ã¯ã€æ–‡å—列ã®é•·ã• ã§åˆæœŸåŒ–ã•ã‚Œã¾ã™ã€‚ 065 * 066 * @param orgStr 処ç†å¯¾è±¡ã®æ–‡å—列 067 * @param stCh é–‹å§‹æ–‡å— 068 * @param edCh çµ‚äº†æ–‡å— 069 */ 070 public JSONScan( final String orgStr, final char stCh, final char edCh ) { 071 this( orgStr, stCh, edCh, 0, orgStr.length() ); 072 } 073 074 /** 075 * コンストラクタ 076 * 処ç†å¯¾è±¡ã®æ–‡å—列を解æžã™ã‚‹ JSONScan ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’作æˆã—ã¾ã™ã€‚ 077 * 078 * @param orgStr 処ç†å¯¾è±¡ã®æ–‡å—列 079 * @param stCh é–‹å§‹æ–‡å— 080 * @param edCh çµ‚äº†æ–‡å— 081 * @param stScan 検索範囲ã®é–‹å§‹ä½ç½® 082 * @param edScan 検索範囲ã®çµ‚了ä½ç½® 083 */ 084 public JSONScan( final String orgStr, final char stCh, final char edCh , final int stScan , final int edScan ) { 085 this.orgStr = orgStr; // 処ç†å¯¾è±¡ã®æ–‡å—列 086 this.stCh = stCh; // é–‹å§‹æ–‡å— 087 this.edCh = edCh; // çµ‚äº†æ–‡å— 088 this.stScan = stScan; // 検索範囲ã®é–‹å§‹ä½ç½® 089 this.edScan = edScan; // 検索範囲ã®çµ‚了ä½ç½® 090 stAdrs = 0; // 処ç†é€”ä¸ã®åˆ‡ã‚Šå‡ºã—開始ä½ç½® 091 edAdrs = stScan; // 処ç†é€”ä¸ã®åˆ‡ã‚Šå‡ºã—終了ä½ç½®(検索範囲ã®æœ€åˆã®ã‚¢ãƒ‰ãƒ¬ã‚¹) 092 } 093 094 /** 095 * 検索範囲ã‹ã‚‰é–‹å§‹æ–‡å—ãŒã¾ã ã‚ã‚‹ã‹ã©ã†ã‹ã‚’判定ã—ã¾ã™ã€‚ 096 * ã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ãŒ true ã‚’è¿”ã™å ´åˆã€ãれ以é™ã®å¼•æ•°ã®ãªã„ next() ã¸ã® 097 * 呼ã³å‡ºã—ã¯é©åˆ‡ã«æ–‡å—列を返ã—ã¾ã™ã€‚ 098 * 099 * @return æ–‡å—列内ã®ç¾åœ¨ã®ä½ç½®ã®å¾Œã‚ã« 1 ã¤ä»¥ä¸Šã®é–‹å§‹æ–‡å—ãŒã‚ã‚‹å ´åˆã ã‘ trueã€ãã†ã§ãªã„å ´åˆã¯ false 100 */ 101 @Override // Iterator 102 public boolean hasNext() { 103 // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドã«ã¯çµ‚了ãƒã‚¤ãƒ³ãƒˆãŒ 1 ã¤ã ã‘å¿…è¦ 104 // 一気ã«åˆ¤å®šã—ã¾ã™ã€‚ 105 stAdrs = orgStr.indexOf( stCh, edAdrs ); 106 edAdrs = orgStr.indexOf( edCh, stAdrs+1 ); 107 108 return stAdrs >= 0 && stAdrs <= edScan && edAdrs >= 0 && edAdrs <= edScan ; 109 110// stAdrs = orgStr.indexOf( stCh, edAdrs ); 111// // 見ã¤ã‹ã‚‰ãªã„ã‹ã€æ¤œç´¢ç¯„囲を超ãˆãŸå ´åˆ 112// if( stAdrs < 0 || stAdrs > edScan ) { 113// return false; 114// } else { 115// edAdrs = orgStr.indexOf( edCh , stAdrs+1 ); 116// // 見ã¤ã‹ã‚‰ãªã„ã‹ã€æ¤œç´¢ç¯„囲を超ãˆãŸå ´åˆ 117// if( edAdrs < 0 || edAdrs > edScan ) { 118// return false; 119// } 120// } 121// return true; 122 } 123 124 /** 125 * 検索範囲ã‹ã‚‰æ¬¡ã®æ–‡å—列を返ã—ã¾ã™ã€‚ 126 * 127 * @return 処ç†é€”ä¸ã®åˆ‡ã‚Šå‡ºã—æ–‡å—列 128 * @throws NoSuchElementException Iteratorã®ç¶™æ‰¿ 129 * 130 * @og.rev 8.5.5.1 (2024/02/29) spotbugs IT_NO_SUCH_ELEMENT (NoSuchElementException ã®è¿½åŠ ) 131 */ 132 @Override // Iterator 133 public String next() { 134 if( orgStr == null ) { 135 final String errMsg = "切り出ã—æ–‡å—列ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“。"; 136 throw new NoSuchElementException( errMsg ); 137 } 138 return orgStr.substring( stAdrs+1 , edAdrs ); 139 } 140 141 /** 142 * 検索範囲ã‹ã‚‰é–‹å§‹æ–‡å—ã®ç¹°ã‚Šè¿”ã—æ•°ã‚’æ•°ãˆã¾ã™ã€‚ 143 * 144 * @return 開始文å—ã®å‡ºç¾å›žæ•° 145 */ 146 public int countBlock() { 147 final String subStr = orgStr.substring( stScan , edScan ); 148 final long cnt = subStr.chars().filter(ch -> ch == stCh).count(); 149 return Math.toIntExact(cnt); 150 } 151 152 /** 153 * JSONå½¢å¼ ã‹ã‚‰ Mapオブジェクト ã«å¤‰æ›´ã—ã¾ã™ã€‚ 154 * 155 * 「カンマ(,)ã€ã¨ã€Œã‚³ãƒãƒ³(:)ã€ã‚ーワードã§åˆ†å‰²ã—ã€ã‚ーã¨ãƒ©ãƒ™ãƒ«ã®ãƒšã‚¢æƒ…å ±ã‚’ 156 * マッピングã—ã¾ã™ã€‚ 157 * 158 * @param csvData JSONå½¢å¼ã®æ–‡å—列 (例:{"key1":"value1","key2":"value2"}) 159 * @return Mapオブジェクト 160 */ 161 public static Map<String,String> json2Map( final String csvData ) { 162 final Map<String,String> map = new HashMap<>(); 163 // 「カンマ(,)ã€ã§åˆ†å‰² 164 final String[] ary = StringUtil.csv2Array( csvData ); 165 for( final String str : ary ) { 166 // 「コãƒãƒ³(:)ã€ã§åˆ†å‰² 167 final String[] kv = str.split(":", 2); 168 if( kv.length == 2 ) { 169 map.put( json2Trim(kv[0]), json2Trim(kv[1]) ); 170 } 171 } 172 return map; 173 } 174 175 /** 176 * Mapオブジェクト ã‹ã‚‰ JSONå½¢å¼ ã«å¤‰æ›´ã—ã¾ã™ã€‚ 177 * 178 * @param prmMap Mapオブジェクト 179 * @return JSONå½¢å¼ã®æ–‡å—列 (例:{"key1":"value1","key2":"value2"}) 180 */ 181 public static String map2Json( final Map<String,String> prmMap ) { 182 final StringBuilder buf = new StringBuilder(BUFFER_MIDDLE); 183 if( prmMap != null ) { 184 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ShortVariable i ⇒ ii ã«å¤‰æ›´ 185 int ii = 0; 186 buf.append( '{' ) 187 .append( CR ); 188 189 for( final Map.Entry<String, String> entry : prmMap.entrySet() ) { 190 if( ii == 0 ) { buf.append( '"' ); } 191 else { buf.append( ",\"" ); } 192 ii++; 193 194 buf.append( entry.getKey() ) 195 .append( "\":\"" ) 196 .append( entry.getValue() ) 197 .append( '"' ) 198 .append( CR ); 199 } 200 buf.append( '}' ); 201 } 202 return buf.toString(); 203 } 204 205 /** 206 * 「カンマ(,)ã€åŒºåˆ‡ã‚Šæ–‡å—ã§é€£çµã•ã‚ŒãŸ String ã‚’ã€é…列ã«åˆ†è§£ã—ã¦ã€ãã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ 207 * ヌル値(null)㯠空白 ã«å¤‰æ›ã—ãŸå€¤ã‚’è¿”ã—ã¾ã™ã€‚ 208 * 209 * @param csvData å…ƒã®ãƒ‡ãƒ¼ã‚¿ 210 * @return æ–‡å—列é…列 211 */ 212 public static String[] json2Array( final String csvData ) { 213 final String[] ary = StringUtil.csv2Array( csvData ); 214 for( int i=0; i<ary.length; i++ ) { 215 ary[i] = "null".equals(ary[i]) ? "" : json2Trim( ary[i] ) ; 216 } 217 return ary; 218 } 219 220 /** 221// * å‰å¾Œã®äºŒé‡å¼•ç”¨ç¬¦(")ã€ä¸æ‹¬å¼§({})ã€ã‚¹ãƒšãƒ¼ã‚¹ã‚’削除ã—ã¾ã™ã€‚ 222 * å‰å¾Œã®äºŒé‡å¼•ç”¨ç¬¦(")ã€ä¸æ‹¬å¼§({})ã€å¤§æ‹¬å¼§([])ã€ã‚¹ãƒšãƒ¼ã‚¹ã€åˆ¶å¾¡æ–‡å—を削除ã—ã¾ã™ã€‚ 223 * 224 * @og.rev 8.1.1.0 (2022/02/04) 大括弧([])ã¨åˆ¶å¾¡æ–‡å—(改行ç‰)も削除対象ã«ã—ã¾ã™ã€‚ 225 * 226 * @param str æ–‡å—列 227// * @return å‰å¾Œã®äºŒé‡å¼•ç”¨ç¬¦(")ã€ä¸æ‹¬å¼§({})ã€ã‚¹ãƒšãƒ¼ã‚¹ã‚’削除ã—ãŸæ–‡å—列 228 * @return å‰å¾Œã®äºŒé‡å¼•ç”¨ç¬¦(")ã€ä¸æ‹¬å¼§({})ã€å¤§æ‹¬å¼§([])ã€ã‚¹ãƒšãƒ¼ã‚¹ã€åˆ¶å¾¡æ–‡å—を削除ã—ãŸæ–‡å—列 229 */ 230 private static String json2Trim( final String str ) { 231 int st = 0; 232 int ed = str.length(); 233 while( st < ed ) { 234 final char ch = str.charAt(st); 235// if( ch == '"' || ch == '{' || ch == '}' || ch == ' ' ) { st++; } 236 if( JSON_TRIM.indexOf(ch) >= 0 || ch < ' ' ) { st++; } // 8.1.1.0 (2022/02/04) 237 else { break; } 238 } 239 while( st < ed ) { 240 final char ch = str.charAt(ed-1); 241// if( ch == '"' || ch == '{' || ch == '}' || ch == ' ' ) { ed--; } 242 if( JSON_TRIM.indexOf(ch) >= 0 || ch < ' ' ) { ed--; } // 8.1.1.0 (2022/02/04) 243 else { break; } 244 } 245 return st < ed ? str.substring(st, ed) : "" ; 246 } 247}