【问题标题】:How to add empty string when 2 delimiters one after another with String.split()使用String.split()一个接一个地添加2个分隔符时如何添加空字符串
【发布时间】:2021-06-06 12:02:49
【问题描述】:

我对正则表达式很陌生,我必须为我正在开发的加载程序拆分 EDI 文件。如果您不熟悉,这里是 2 个片段的示例(已修改以解释所有内容,因此它不是一个真实示例):

APD+EM2:0:16?'30::6+++++++DA'APD+EM2:0:1630::6+++++++DA'

行尾标有',如果有作为问号的转义字符,我会忽略 - 例如,?' 将忽略行尾。 \+: 是主要的分隔符(当数据像地址一样组合时)。

段的拆分工作正常,但其他分隔符有问题。我想要一个包含所有元素的String[],即使它们是空的,因为我需要在之后处理它(插入数据库)。对于上面的例子,我想要一个这样的标签:

APD+EM2:0:16?'30::6+++++++DA

会变成:

{"APD","EM2","0","16?'30","","6","","","","","","","DA"}

目前使用我的代码,我得到一个像这样的标签:

{"APD","EM2","0","16?'30","6","DA"}

我可以对我的正则表达式提供一些帮助吗?使其匹配++:: 目前超出了我的技能范围。我还需要删除转义字符,但我会自己处理。

顺便说一句,我需要处理大量数据 - 300gb 的原始文本 - 所以如果我所做的在性能方面很差,请不要犹豫告诉我 - 就像每个示例都拆分为 + 和 @987654339 @同时。

EDIFACT 格式在这里讨论得不多,我发现的几个例子对我不起作用。

当前代码:

private final String DATA_ELEMENT_DELIMITER = "(?<!\\?)\\+";
private final String DATA_COMPOSITE_ELEMENT_DELIMITER = "(?<!\\?):";

private String[] split (String segments){       
    return Stream.of(segments)
            .flatMap(Pattern.compile(DATA_ELEMENT_DELIMITER)::splitAsStream)
            .flatMap(Pattern.compile(DATA_COMPOSITE_ELEMENT_DELIMITER)::splitAsStream)
            .toArray(String[]::new);
}

编辑: 我正在运行的代码 - 顺便说一句,我在 Java 8 上运行,但不确定它是否有所作为:

import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class Split {

    public static void main(String[] args) {
        Split s = new Split();
        System.out.println(
                Arrays.toString(
                    s.split("APD+EM2:0:16?'30::6+++++++DA'")
                )
            );
    }
    
    
    private static final Pattern DATA_ELEMENT_DELIMITER = Pattern.compile("(?<!\\?)\\+");
    private static final Pattern DATA_COMPOSITE_ELEMENT_DELIMITER = Pattern.compile("(?<!\\?):");
    
    private String[] split (String segments){       
        return Stream.of(segments)
                .flatMap(DATA_ELEMENT_DELIMITER::splitAsStream)
                .flatMap(DATA_COMPOSITE_ELEMENT_DELIMITER::splitAsStream)
                .toArray(String[]::new);
    }
}

这是我得到的输出:

[APD, EM2, 0, 16?'30, , 6, DA']

编辑编辑

尝试在在线 Java 11 编译器中运行此代码后,输出正确,但在 Java 8 上不正确。

【问题讨论】:

  • 一般来说,我建议不要使用正则表达式来解析 Edifact 文档,除非您可以确保您的字符集不使用(可变长度)多字节编码,例如 UNOXUNOYKECA 即如果你还想使用正则表达式,整个表达式很快就会变得难以阅读,就像 thisthat 示例展示
  • 不清楚问题出在哪里,将"APD+EM2:0:16?'30::6+++++++DA" 输入您的代码会返回[APD, EM2, 0, 16?'30, , 6, , , , , , , DA] (Ideone)
  • @Roman 那你会推荐什么?构架 ? user15244370 好吧......在我这边,这不是正在发生的事情哈哈
  • 我目前正在开发一个 Java 原生 Edifact 解析器,当它准备好时可能是开源的(取决于我的员工)。它基本上只是一个增强了node-edifactts-edifact 库的端口。不幸的是,它们现在都不真正支持多字节编码。在那之前,最好的选择可能是推荐的 Smooks 和 X12 here
  • 感谢您的回答。您的项目是否有名称,以便我可以在将来检查它变成什么并可能将其集成到我的项目中?我在使用库读取/解析 edifact 时遇到问题,因为我收到的文件不遵循 X12 等标准格式,它只是原始数据:/ 我尝试使用 StAEDI 1st,但我的 EDI 中没有 UNA 或 UNB,所以不想读过,但我没有尝试,但我想其他框架也是一样的 - 由于这个原因,现在正则表达式是我要走的路

标签: java regex data-processing edifact


【解决方案1】:

我的第一个注意事项是,为了提高性能,您肯定希望编译一次 Patterns 并重用该实例:

private static final Pattern DATA_ELEMENT_DELIMITER = Pattern.compile("(?<!\\?)\\+");
private static final Pattern DATA_COMPOSITE_ELEMENT_DELIMITER = Pattern.compile("(?<!\\?):");
// ...
.flatMap(DATA_ELEMENT_DELIMITER::splitAsStream)
.flatMap(DATA_COMPOSITE_ELEMENT_DELIMITER::splitAsStream)

其次,正如@user15244370 所提到的,运行您的代码确实会产生您正在寻找的输出。我是这样运行的:

System.out.println(
    Arrays.toString(
        split("APD+EM2:0:16?'30::6+++++++DA'APD+EM2:0:1630::6+++++++DA'")
    )
);

并得到输出:

[APD, EM2, 0, 16?'30, , 6, , , , , , , DA'APD, EM2, 0, 1630, , 6, , , , , , , DA']

假设您发布的内容与实际运行的内容之间存在一些差异,splitAsStream 的文档提到:

尾随的空字符串将被丢弃并且不会在流中遇到。


在调用split 之后,您是否正在做任何额外的处理?你是如何打印数组的?您用于打印string[] 的方法是否可能正在删除空字符串?据我所知,您的实现应该按您的意愿运行。

【讨论】:

  • 感谢您的编译,每次编译一次肯定比每次尝试将其移出类时要好,因为我想确保没有其他任何东西干扰我的代码。我添加了我在原始帖子中使用的代码
猜你喜欢
  • 1970-01-01
  • 2020-04-13
  • 2013-06-19
  • 1970-01-01
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多