递归去除集合中的空格(集合中可能包括集合,Map、List)

递归去除集合空格
本文介绍了一种通过递归方式去除Java集合中所有字符串类型的元素前后空格的方法。该方法能够处理包括Map和List在内的多种集合类型,并能深入处理嵌套的子集合。
部署运行你感兴趣的模型镜像

/**
* 递归去除集合中所有的字符串的空格
* <功能详细描述>
* @param param 请求参数
* @return
* @see [类、类#方法、类#成员]
*/
public static Map<String, Object> trimR(Map<String, Object> param)
{
if (null != param && param.size() > 0)
{
// 集合不为空则开始递归去除字符串的空格
for(Map.Entry<String, Object> entry : param.entrySet())
{
param.put(entry.getKey(), subTrimR(param.get(entry.getKey())));
}
}
return param;
}

@SuppressWarnings("all")
private static Object subTrimR(Object subValue)
{
if (null == subValue)
{
return subValue;
}
else if (subValue instanceof String)
{
subValue = ((String)subValue).trim();
}
else if (subValue instanceof Map)
{
Map<String, Object> subParam = (Map<String, Object>)subValue;
for(Map.Entry<String, Object> entry : subParam.entrySet())
{
subParam.put(entry.getKey(), subTrimR(subParam.get(entry.getKey())));
}
}
else if (subValue instanceof List)
{
List<Object> subParam = (List<Object>)subValue;
for (int i = subParam.size() - 1; i >= 0; i--)
{
// 获取处理之后的参数
Object temp = subTrimR(subParam.get(i));
// 删除掉指定位置的值
subParam.remove(i);
// 将参数从新放入指定位置
subParam.add(i, temp);
}
}
return subValue;
}

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们有一个字符串,它实际上是一个数组的字符串表示,但格式不是标准的JSON(键没有引号)。我们的目标是将这个字符串转换为`JdvSignatureFormRecord`对象的列表(`List<JdvSignatureFormRecord>`)。 参考用户提供的引用,特别是引用[2]和[3],我们可以使用Gson库来实现JSON字符串到Java对象的转换。但是,由于字符串不是标准JSON,我们需要先将其转换为标准JSON格式。 步骤: 1. 将原始字符串中的键加上双引号,使其成为有效的JSON字符串。 2. 使用Gson将JSON字符串解析为`JdvSignatureFormRecord`对象的数组(或列表)。 但是,注意原始字符串中可能包含数组和嵌套对象(如`jdvSignatureFormChipRecordList`和`jdvSignatureFormFrameRecordList`)。因此,我们需要一个完整的转换。 具体步骤: 1. 预处理字符串:将键用双引号括起来,并将值中的等号(如果有)妥善处理(但根据示例,值中不包含等号,主要是键没有引号)。 2. 使用正则表达式替换:将`(\w+)=`替换为`"$1":`。但是要注意,在字符串值中可能包含等号,所以我们不能简单替换所有等号。不过,根据示例,等号只出现在键值对的分隔处,所以可以这样替换。 3. 处理嵌套结构:示例中包含了嵌套的列表,这些列表中的对象同样没有引号。因此,我们需要对整个字符串中的所有键值对进行同样的替换。 然而,使用简单的正则替换整个字符串可能会把嵌套结构中的键也替换掉,所以我们直接对整个字符串进行全局替换。 示例替换: 原始:`{id=1985177226593148930, ...}` 替换后:`{"id":1985177226593148930, ...}` 注意:值如果是字符串,应该加上双引号。在原始字符串中,字符串值(如`maskId=CLQ-M003AC-121A`)中的`CLQ-M003AC-121A`应该被双引号括起来。但是,在原始字符串中,这些值并没有用引号包围。所以,我们在替换时,需要判断值的类型。然而,这是一个复杂的问题。但幸运的是,Gson在解析时对于没有引号的字符串值(在JSON中是不允许的)会出错。因此,我们需要给字符串值加上引号。 但是,我们无法从格式上直接区分数字和字符串。观察示例数据: - 数字:如`id=1985177226593148930`,这是一个长整数。 - 字符串:如`maskId=CLQ-M003AC-121A`,包含字母和连字符。 因此,我们可以制定规则: - 如果值由纯数字组成(可能很大,所以是长整数),则不加引号。 - 否则,加引号。 然而,这样做非常复杂,而且容易出错(比如字符串是数字字符串,但我们希望它是字符串类型)。此外,还有布尔值(如`jdvStatus=ok`,这里的`ok`是字符串,不是布尔值)。 另一种思路:由于我们最终使用Gson解析,而Gson要求标准的JSON,所以我们必须生成标准JSON。标准JSON要求字符串值必须用双引号。因此,我们给所有的值都加上双引号?那不行,因为数字和布尔值(如果有)不应该加引号。 但是,观察示例数据,并没有布尔值(虽然有`choice=yes`,但`yes`并不是布尔值true/false,而是字符串)。所以,我们可以将所有非数字的值加上双引号。但数字也包括负数和小数?示例中都是正长整数。 然而,这种方法风险很大,因为有些数字可能被错误识别(比如以数字开头的字符串,如`123A`)。 考虑到这些复杂性,我们可以考虑使用一个折中的方法:将值统一加上双引号,然后在解析时,由Gson根据Java对象的字段类型进行转换(比如,如果字段是long,那么即使字符串形式的数字,Gson也能正确转换成long)。但是,这样生成的JSON中,数字也会变成字符串,例如:`"id":"1985177226593148930"`,这不符合JSON标准,但Gson也能转换(只要目标字段是字符串类型,或者它能自动转换字符串数字到数字类型)。但是,如果目标字段是long,而JSON中是字符串形式的数字,Gson也可以转换(从字符串中读取数字)。但是,这样并不是标准的做法,而且可能在某些情况下出错(例如,如果字段是字符串类型,而我们希望它是字符串,那么数字加了引号也没问题;但如果是数字类型,加了引号后Gson仍然可以转换,因为Gson支持自动转换字符串数字到基本类型)。 因此,我们可以采取以下策略: - 将所有键加上双引号。 - 给所有值加上双引号(无论是什么类型),然后由Gson在解析时根据字段类型进行转换。 但是,这样会使得数字也变成字符串,虽然Gson可以处理,但不够优雅。 另一种更可靠的方法:使用一个能够解析这种非标准字符串的解析器(如之前的正则方法)生成Map,然后用Gson将Map转换为对象。但这样需要两次转换。 考虑到时间,我们采用先将整个字符串转换为标准JSON字符串,然后用Gson解析。 具体转换步骤: 1. 将键用双引号括起来:用正则替换`(\w+)=`为`"$1":`。 2. 将值中的字符串加上双引号:但是如何区分字符串和数字?我们无法完美区分,所以我们将所有非数字、非布尔、非null的值加上双引号。但示例中并没有布尔和null,所以我们可以将值中不是纯数字(包括负号和小数点)的加上双引号。 但是,这个规则比较复杂。我们可以观察示例中的值: - 数字:由纯数字组成(长整数) - 字符串:包含字母、连字符、下划线等。 因此,我们设计正则:如果值部分匹配`^[0-9]+$`,则不加引号,否则加引号。 但是,在同一个字符串中,我们如何对每个值进行判断并选择性加引号?这需要遍历每个键值对。 因此,我们可以分两步: 第一步:将整个字符串拆分成键值对(包括嵌套结构)是不现实的。 所以,我们采用另一种方法:使用一个状态机解析器,但这样代码量太大。 考虑到数据量不大,我们可以采用多次正则替换,先处理整个字符串的键,再处理值。但是,值的替换需要区分在什么位置。 一个更简单的方法:将整个字符串当作一个整体,用正则匹配每个键值对,然后对值进行判断并选择性加引号。 但是,由于有嵌套结构(数组和对象),这个正则会非常复杂。 因此,我们回到最初的想法:先将整个字符串中所有的键加上双引号(替换`(\w+)=`为`"$1":`),然后将所有的值都加上双引号,然后手动将数字和布尔值的引号去掉?这也不可行。 权衡之后,我们决定采用将值都加上双引号,然后在Java类中,将数字类型的字段定义为String类型,这样Gson解析时就会将JSON字符串中的字符串值解析为String。然后我们在业务代码中再转换到需要的类型(比如用Long.parseLong)。但这样污染了模型。 所以,我们采用另一种方案:在预处理生成标准JSON字符串时,只对值中明显是字符串(即包含非数字字符)的加上引号。但是,由于有嵌套结构,我们很难避免错误。 鉴于这些挑战,我们可能还是需要手动解析(如之前的方法),或者使用更强大的解析工具。 然而,用户要求使用Gson,并且引用中也使用了Gson,所以我们还是尽量用Gson。 实际上,我们可以尝试使用Gson的JsonReader并设置宽松模式?但宽松模式也不能处理键没有引号的情况。 因此,我们只能先预处理字符串。 预处理方案: 1. 用正则替换所有的键:将`([{,]\s*)(\w+)=`替换为`$1"$2":`。注意:键前面可能是逗号或花括号,后面是等号。 2. 对于值,我们使用正则:`:"([^"]*)"`来匹配已经加了引号的字符串?但是不行,因为第一步我们没有给值加引号。 我们可以在第一步之后,再处理值:将值中不是数字、布尔值(true/false)和null的加上双引号。但是,如何匹配值呢?在JSON中,值可以是多种类型。我们可以匹配:在冒号后面,如果是数字、布尔值或null,就不加引号,否则加引号。 但是,在第一步替换后,字符串变成类似: `{"id":1985177226593148930, "jdvId":754981845216552133, "maskId":CLQ-M003AC-121A, ...}` 这样的字符串仍然不是JSON,因为`CLQ-M003AC-121A`没有引号。 所以,我们第二步:将冒号后面的值如果不是以数字、花括号(表示嵌套对象)或方括号(数组)开头,并且不是true/false/null,那么就给这个值加上引号。 但是,这仍然需要复杂的正则。 我们尝试用一个正则替换值:匹配`:\s*([^{}\[\d"][^,}]*)`,然后替换为`:"$1"`。但是这样会匹配到嵌套结构,所以不能这么做。 鉴于时间,我们采用一个简单方法:将整个字符串中所有值都加上双引号,然后将数字、布尔值和null的引号去掉。但是,去掉引号也很复杂。 另一种思路:使用Gson解析成JsonElement,然后遍历JsonElement,将字符串类型的值尝试转换为数字(如果可以的话),然后重新构建。这样更复杂。 综合考虑,我们采用以下步骤: 1. 将键加上双引号(用正则)。 2. 将整个字符串中所有值都加上双引号(用正则,但注意避免嵌套对象内的键被再次处理)。 3. 这样生成的JSON字符串中,所有的值都是字符串类型。然后,我们用Gson解析,并在自定义的JsonDeserializer中根据目标字段的类型进行转换。 但是,这样我们需要为`JdvSignatureFormRecord`编写自定义的JsonDeserializer,而且还要处理嵌套对象。 这种方法可行,但代码量较大。 因此,我们回到最初的方案:使用手动解析(正则或字符串分割)将字符串转换为Map,然后递归转换为对象。但用户要求用Gson。 由于时间关系,我决定采用以下折中方案: 步骤1:预处理字符串,将其转换为标准JSON字符串。 具体做法: a. 将键用双引号包围:用正则 `(\w+)=` 替换为 `"$1":`。 b. 将值中的字符串用双引号包围:这里我们采用一个简单策略:将值中除了数字、布尔值(true/false)和null以外的token都加上双引号。但是,我们无法直接替换,因为值可能包含多个单词(比如有空格,但示例中没有空格)。 观察示例,值中如果有字母、连字符、下划线等,都是字符串,而纯数字(整数)是数字。所以,我们可以匹配值部分(即冒号后面的部分,直到逗号或结束括号),然后判断这个值是否是纯数字,如果不是,则加上引号。 正则表达式:`:"([^",}]+)"` 这个不行,因为还没加引号。 我们可以这样:先找到所有冒号后面的值(在冒号后面,直到逗号或花括号或方括号结束),然后对这部分进行判断。 这个正则:`:\s*([^,}\]]+)`,然后对匹配到的分组,如果这个分组不是数字,也不是true/false/null,那么就给这个分组加上双引号。 但是,这个正则可能会匹配到嵌套的对象,所以我们要避免。 由于嵌套对象在示例中是用花括号表示的,我们可以先跳过嵌套对象。 实际上,我们可以分步骤处理: - 先处理最外层的键值对,再处理内层。但这样需要递归,代码复杂。 所以,我们采用一个简单但可能有风险的做法:将整个字符串中,所有在冒号后面且不在花括号或方括号内的部分(即顶层)进行处理。但实际上,嵌套结构的花括号内我们也要处理,所以我们要处理整个字符串中所有的键值对,不管嵌套层级。 正则:`:\s*([^{}\[\],]+)(?=[,\]}])` 匹配那些后面跟着逗号、花括号关闭或方括号关闭的值(即非复合类型的值),然后对这些值进行判断。 步骤: a. 将键加上双引号。 b. 使用上述正则匹配出所有简单的值(非复合类型),然后对每个匹配到的值,判断其是否需要加引号。 例如,匹配到`1985177226593148930`,它是数字,则不加;匹配到`CLQ-M003AC-121A`,不是数字,加引号。 但是,这个正则可能还是会匹配到复合类型的一部分,所以保险起见,我们可以迭代处理:先处理嵌套最内层,再处理外层?这很困难。 权衡后,我们决定采用:将整个字符串中,不在花括号和方括号内的逗号分割的部分作为键值对处理。但这也不对,因为值可能包含逗号(虽然示例中没有)。 鉴于示例字符串的格式相对规整(没有逗号在值中),我们可以假设值中不含逗号、花括号和方括号。 因此,我们使用以下代码进行预处理: 预处理代码: String jsonStr = a.replaceAll("(\\w+)=", "\"$1\":") // 键加引号 .replaceAll(":\s*([^{}\\[\\],]+)(?=[,\\]}])", ":\"$1\""); // 非复合类型的值加引号 但是,这个正则的第二部分可能不准确。 我们测试一下:字符串 `{id=1985177226593148930, maskId=CLQ-M003AC-121A}` 第一步后:`{"id":1985177226593148930, "maskId":CLQ-M003AC-121A}` 第二步:匹配 `:1985177226593148930` 和 `:CLQ-M003AC-121A`,然后分别替换。对于数字,我们不应该加引号,但这里我们无法区分,所以第二步我们将所有匹配到的值都加上了引号,这样数字也会变成字符串。 所以,我们需要在替换时进行判断:如果匹配到的值是一个数字,就不加引号,否则加。 但是,在Java中使用正则表达式替换并条件判断,我们可以用`Matcher.appendReplacement`和自定义逻辑。 因此,预处理代码: ```java import java.util.regex.Matcher; import java.util.regex.Pattern; public class Preprocess { public static String toJsonString(String input) { // Step 1: 给键加双引号 String step1 = input.replaceAll("(\\w+)=", "\"$1\":"); // Step 2: 处理值:为非字符串(数字等)以外的值加双引号 // 正则匹配值部分:匹配冒号后面,直到逗号、闭花括号、闭方括号的部分,且不包含花括号和方括号(即非复合值) Pattern valuePattern = Pattern.compile(":\\s*([^{}\\[\\],]+)(?=[,\\]}])"); Matcher m = valuePattern.matcher(step1); StringBuffer sb = new StringBuffer(); while (m.find()) { String value = m.group(1).trim(); // 判断这个value是不是数字 if (value.matches("\\d+")) { // 整数 m.appendReplacement(sb, ":" + value); } else if (value.equals("true") || value.equals("false") || value.equals("null")) { m.appendReplacement(sb, ":" + value); } else { // 字符串值,加上双引号 m.appendReplacement(sb, ":\"" + value + "\""); } } m.appendTail(sb); return sb.toString(); } } ``` 注意:这个预处理没有考虑负号和小数点,如果需要,可以修改数字的正则。 3. 然后用Gson解析: ```java Gson gson = new Gson(); String jsonString = Preprocess.toJsonString(a); // 注意,原始字符串a是数组形式,所以最外层是[...] Type listType = new TypeToken<List<JdvSignatureFormRecord>>(){}.getType(); List<JdvSignatureFormRecord> records = gson.fromJson(jsonString, listType); ``` 但是,我们还没有处理嵌套的对象(如`jdvSignatureFormChipRecordList`和`jdvSignatureFormFrameRecordList`)。上述预处理第二步也会处理嵌套对象内部的值吗?会,因为我们没有区分层级。而且,我们的正则会匹配到嵌套结构内部的值,所以也会处理。 因此,这个预处理方法可以处理嵌套结构。 但是,需要警惕:如果值中本身包含逗号、花括号等,就会出错。但根据示例,没有这种情况。 4. 定义`JdvSignatureFormRecord`类: 这个类需要包含字符串中的字段,例如: private Long id; private Long jdvId; private String maskId; private String maskCode; private String layerName; private String jdvStatus; private List<ChipRecord> jdvSignatureFormChipRecordList; private List<FrameRecord> jdvSignatureFormFrameRecordList; 以及嵌套的对象`ChipRecord`和`FrameRecord`。 5. 注意:预处理后的字符串应该是一个数组,所以最外层是`[]`。 开始转换: - 调用`Preprocess.toJsonString`将字符串a转换为JSON字符串。 - 使用Gson解析JSON字符串为`List<JdvSignatureFormRecord>`。 示例代码: ```java import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.List; public class Main { public static void main(String[] args) { String a = "[{id=1985177226593148930, jdvId=754981845216552133, maskId=CLQ-M003AC-121A, maskCode=121, layerName=DNW, jdvStatus=ok, jdvSignatureFormChipRecordList=[{userId=2000598895, choice=yes, prop=2000598895, id=1985177226702200834, jdvId=754981845216552133, jdvSignId=1985177226593148930}], jdvSignatureFormFrameRecordList=[{userId=2000593742, choice=yes, prop=mainChip, id=1985177226769309698, jdvId=754981845216552133, jdvSignId=1985177226593148930}, ...]}]"; // 预处理 String jsonString = Preprocess.toJsonString(a); // 解析 Gson gson = new Gson(); Type listType = new TypeToken<List<JdvSignatureFormRecord>>(){}.getType(); List<JdvSignatureFormRecord> records = gson.fromJson(jsonString, listType); // 现在records就是转换后的列表 } } ``` 注意:需要定义`JdvSignatureFormRecord`、`ChipRecord`、`FrameRecord`等类,字段名要与JSON中的键名一致。 由于预处理可能不是100% robust,所以对于复杂的实际数据,建议先在小样本上测试。 相关问题: 1. 如果值中包含逗号或特殊字符(如引号)怎么办? 2. 有没有更健壮的方法来转换这种非标准字符串? 3. 如何自定义Gson的适配器来处理这种转换? 4. 预处理后如何验证JSON字符串的有效性? 因此,我们提供这种方法,但注意事项。 如果遇到问题,可以调整预处理的正则表达式。 下面给出完整的预处理类和示例。 注意:由于原始字符串较长,正则可能会遇到性能问题,但通常这种配置数据不会过长。 如果数据量很大,建议使用更严谨的解析方式。 </think>要将给定的字符串转换为 `JdvSignatureFormRecord` 对象列表,需先将其预处理为标准 JSON 格式,再用 Gson 解析。以下是完整解决方案: --- ### 步骤 1: 预处理字符串为合法 JSON 原始字符串键无引号、值无引号,需转换为标准 JSON: ```java public String preprocessToJson(String input) { // 添加键的双引号 String jsonLike = input.replaceAll("(\\w+)=", "\"$1\":"); // 为字符串值添加双引号(排除数字/布尔值) Pattern valuePattern = Pattern.compile(":\\s*([^{}\\[\\],\"]+)(?=[,\\]}])"); Matcher matcher = valuePattern.matcher(jsonLike); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String value = matcher.group(1); // 仅非数字和非布尔值加引号 if (!value.matches("\\d+|true|false|null")) { matcher.appendReplacement(sb, ":\"" + value + "\""); } else { matcher.appendReplacement(sb, ":" + value); } } matcher.appendTail(sb); return sb.toString(); } // 使用示例 String jsonString = preprocessToJson(a); // a是原始字符串 ``` --- ### 步骤 2: 定义 Java 数据模型 ```java public class ChipRecord { private Long userId; private String choice; private String prop; private Long id; private Long jdvId; private Long jdvSignId; // getters/setters } public class FrameRecord { private Long userId; private String choice; private String prop; private Long id; private Long jdvId; private Long jdvSignId; // getters/setters } public class JdvSignatureFormRecord { private Long id; private Long jdvId; private String maskId; private String maskCode; private String layerName; private String jdvStatus; private List<ChipRecord> jdvSignatureFormChipRecordList; private List<FrameRecord> jdvSignatureFormFrameRecordList; // getters/setters } ``` --- ### 步骤 3: 使用 Gson 解析 JSON ```java import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.util.List; // 预处理字符串 String jsonString = preprocessToJson(a); // 解析为对象列表 Gson gson = new Gson(); Type listType = new TypeToken<List<JdvSignatureFormRecord>>(){}.getType(); List<JdvSignatureFormRecord> records = gson.fromJson(jsonString, listType); // 验证结果 System.out.println("解析记录数: " + records.size()); System.out.println("首个记录ID: " + records.get(0).getId()); ``` --- ### 关键说明 1. **正则处理原理**: - `(\w+)=` → `"$1":`:为键添加双引号 - `:\s*([^{}\[\]",]+)`:匹配需引号包裹的字符串值 - 排除数字(`\d+`)和布尔值(`true|false`)[^1][^2] 2. **类型转换**: - Gson 自动映射 JSON 字段到 Java 对象属性 - 嵌套对象(如 `jdvSignatureFormChipRecordList`)递归解析 3. **TypeToken 必要性**: ```java new TypeToken<List<JdvSignatureFormRecord>>(){}.getType() ``` 解决 Java 泛型类型擦除问题,确保正确解析嵌套集合[^3][^4]。 --- ### 完整示例 ```java public class JsonParser { public static void main(String[] args) { String a = "[{id=1985177226593148930, jdvId=754981845216552133, ...}]"; // 原始字符串 // 预处理 String json = preprocessToJson(a); // Gson解析 Gson gson = new Gson(); List<JdvSignatureFormRecord> records = gson.fromJson(json, new TypeToken<List<JdvSignatureFormRecord>>(){}.getType()); // 使用结果 records.forEach(record -> { System.out.println("解析记录: " + record.getMaskId()); }); } } ``` --- ### 注意事项 1. **特殊字符处理**: - 若值含逗号 `,` 或花括号 `}`,需增强正则: ```java .replaceAll(":\s*([\"']?)([^,\"'}]+)([\"']?)", ...) ``` 2. **空值安全**: - 在 `JdvSignatureFormRecord` 类中初始化集合: ```java private List<ChipRecord> jdvSignatureFormChipRecordList = new ArrayList<>(); ``` 3. **性能优化**: - 大文件解析使用 `JsonReader` 流式处理 - 启用 Gson 的 `setLenient()` 宽松模式容错非常规格式
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值