根据下一个词在一行中查找一个词

Find a word in a line based on next word

我有一个文件,这里是文件的一部分。所有行中的公共词在这里都是PIC,我可以找到PIC的索引。我正在尝试提取每一行的描述。在这里我如何提取 PIC 之前的单词?

          15 EXTR-SITE                                 PIC X.
        05 EXTR-DBA                                    PIC X.
TE0305*     05 EXTR-BRANCH                         PIC X(05).
TE0305*     05 EXTR-NUMBER                         PIC X(06).
TE0305      05 FILLER                                  PIC X(11).
CW0104        10 EXTR-TEXT6                       PIC X(67).
CW0104        10 EXTR-TEXT7                       PIC X(67).
CW0104*     05 FILLER                                  PIC X(567).

我必须得到如下结果

EXTR-SITE 
EXTR-DBA
EXTR-NUMBER
-------
FILLER

有什么表达式可以用来找到 'PIC' 之前的词吗?

这是我的代码,用于获取包含 'PIC':

的行
int wordStartIndex = line.indexOf("PIC");
int wordEndIndex = line.indexOf(".");
if ((wordStartIndex > -1) && (wordEndIndex >= wordStartIndex)) {
System.out.println(line); }

您可以像这样尝试正则表达式:

public static void main(String[] args) {
    String s = "15 EXTR-SITE                                 PIC X.";
    System.out.println(s.replaceAll("(.*?\s+)+(.*?)(?=\s+PIC).*", ""));
}

O/P:

EXTR-SITE

解释:

(.*?\s+)+(.*?)(?=\s+PIC).*", "") :

(.*?\s+)+ --> Find one or more groups of "anything" which is followed by a space.

(.*?)(?=\s+PIC) -->find a group of "any set of characters" which are followed by a space and the word "PIC".
.* --> Select everything after PIC.

 --> the contents of the actual String with the first captured group i.e, data between `()`.

PS :这适用于您当前的所有输入:P

//let 'lines' be an array of all your lines 
//with one complete line as string per element

for(String line : lines){ 
   String[] splitted = line.split(" ");
   for(int i = 0; i < splitted.length; i++){
       if(splitted[i].equals("PIC") && i > 0) System.out.println(splitted[i-1]);
   }
}

请注意,我还没有测试这段代码(但会在几分钟后)。但是,现在一般方法应该很清楚了。

尝试使用String.split("\s+")。此方法将原始字符串拆分为一个字符串数组 (String[])。然后,使用 Arrays.asList(...) 可以将数组转换为 List,因此您可以使用 indexOf.

搜索特定对象

以下是可能解决方案的摘录:

String words = "TE0305*     05 EXTR-BRANCH                         PIC X(05).";
List<String> list = Arrays.asList(words.split("\s+"));
int index = list.indexOf("PIC");
// Prints EXTR-BRANCH
System.out.println(index > 0 ? list.get(index - 1) : ""); // Added a guard

老实说,这段代码让 Java 为您工作,而不是相反。它简洁、可读,然后更可维护.

          15 EXTR-SITE                                 PIC X.
        05 EXTR-DBA                                    PIC X.
TE0305*     05 EXTR-BRANCH                         PIC X(05).
TE0305*     05 EXTR-NUMBER                         PIC X(06).
TE0305      05 FILLER                                  PIC X(11).
CW0104        10 EXTR-TEXT6                       PIC X(67).
CW0104        10 EXTR-TEXT7                       PIC X(67).
CW0104*     05 FILLER                                  PIC X(567).

我认为您在完成此任务之前需要了解更多有关 COBOL 的信息。

第 1-6 列可以包含序号,可以为空,也可以包含任何内容。如果您尝试解析 COBOL 代码,则需要忽略第 1-6 列。

第 7 列称为指标区域。它可以是空白的,或者包含一个 * 表示注释,或者一个 -,表示该行是前一个 non-blank/non-comment 行的延续,或者包含一个 D 表示它是一条调试线。

第 73-80 列可能包含其他序列号、空白或任何内容,必须忽略。

如果您的 COBOL 源代码是 "free format",情况会有所不同,但事实并非如此。

从注释行中提取数据没有任何意义,因此您的预期输出无效。还不清楚您在预期输出中从何处获得破折号。

如果您尝试解析 COBOL 源代码,则必须具有有效的 COBOL 源代码。这是无效的:

TE0305      05 FILLER                                  PIC X(11).
CW0104        10 EXTR-TEXT6                       PIC X(67).
CW0104        10 EXTR-TEXT7                       PIC X(67).

如果级别编号(05)后面跟着更高级别的编号(两个 10),则它是一个组项目。组项目不能有图片。

PIC本身也可以写全,如PICTURE

PIC 很容易出现在 identifier/data-name (EPIC-CODE) 中。理论上,PICTURE 也可以。

PIC 和 PICTURE 可以出现在注释行中,即使不是注释的代码行。

您要用来查找 "description"(标识符或数据名称)的方法有缺陷。

   01  the-record.
       05  fixed-part-of-record.
           10  an-individual-item PIC X.
           10  another-item COMP-1.
           10  and-another COMP-3 PIC 9(3).
           10  PIC X.
       05  variable-part-of-record.
           10  entry-name OCCURS 10 TIMES.
               15  entry-name-client-first-name
                                  PIC X(30).
               15  entry-name-client-surname
                                  PIC X(30).

这只是一个简短的例子,不能被认为是包罗万象的。

由此,您的方法将检索

an-individual-item
COMP-3
and two lines of "whatever happens when PIC is the first thing on line"

为了避免这个问题变成变色龙问题,您需要用不同的方法提出一个新问题(或自己解决)。

根据 COBOL 源的来源,有更好的方法来处理这个问题。如果源代码是 IBM 大型机 COBOL,那么您的源代码应该是编译列表或编译中的 SYSADATA。

从其中任何一个,您都可以在特定条件下的特定位置拿起 identifier/data-name。根本不需要解析。

如果你找不到那个,那我建议你找level-number,然后找到第一个。你还有一些工作要做。

Level-numbers 可以是一位或两位数字,在 1-49 范围内,加上 66、77、88。有些编译器也有 78。如果您的摘录只有 "records"(可能),您就赢了看不到 77 或 78。您可能看不到 66(只看到它使用过一次),很可能会看到 88,您可能希望或可能不希望将其包含在输出中(取决于您需要它的目的)。

1.
01.
01  FILLER.
01  data-name-name-1.
01  data-name-name-2 PIC X(80).
    5.
    05.
    05  FILLER.
    05  FILLER PIC X.
    05  data-name-name-3.
    05  data-name-name-4 PIC X.

使用单个数字表示级别编号而不明确拼写 FILLER 是相当 "new"(来自 1985 年标准),您很可能没有这些。但你可能会。

上面的输出应该是:

FILLER
FILLER
FILLER
data-name-name-1
data-name-name-2
FILLER
FILLER
FILLER
FILLER
data-name-name-3
data-name-name-4

我不知道你想用那个输出做什么。没有上下文,它没有太多意义。

您选择的方法可能适用于您的实际数据(假设您对样本进行了 pickle,并且您得到的是有效代码)。

不过,说"if the first word on a line is one- or two-digit numeric, if there is a second word, that's what we want, else use FILLER"还是比较简单的。当然,请注意之前关于您应该忽略的内容的评论。

除非您的源包含 88 个级别。因为一系列值需要第二行是很常见的,如果这些值恰好是数字,一个或两个数字,那么这也不起作用。

因此,请确定您的来源。如果它是 IBM 大型机,请尝试从编译中获取输出。那你的任务真的很简单,而且100%准确。

如果你做不到,那就彻底了解你的数据。如果你的结构真的很简单,那么你的方法就可以工作,从级别数开始做仍然会更容易。

如果您需要回到这里,请提出一个新问题。否则你就是在和那些已经花时间自愿回答你现有问题的人闲逛。

如果您不打算自己编写 Cobol 解析器,有几个选项包括:

  • 使用Cobol Compiler处理Cobol copybook。这将以更易于解析的格式创建 Cobol-Copybook 列表。我曾在一些公司工作,这些公司通过在 Hello-World 类型程序中编译 Cobol-Copybook 并处理输出,将所有 Cobol-Copybook 自动转换为等效的 easytrieve copybook。

  • File-Aid 这样的产品有一个 Cobol 解析器,可以生成一个易于理解的 Cobol Copybook 版本。

  • java 项目 cb2xml 会将 Cobol-Copybook 转换为 Xml。该项目提供了一些使用 Jaxb 处理 Xml 的示例。


使用 cb2xml(取自 Demo2.java)将 Cobol-Copybook 解析为 Java 项列表:

JAXBContext jc = JAXBContext.newInstance(Condition.class, Copybook.class, Item.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Document doc = Cb2Xml2.convertToXMLDOM(
                       new File(Code.getFullName("BitOfEverything.cbl").getFile()),
                       false,
                       Cb2xmlConstants.USE_STANDARD_COLUMNS);
JAXBElement<Copybook> copybook = unmarshaller.unmarshal(doc, Copybook.class);

然后程序Demo2.java会打印cobol copybook的内容:

List<Item> items = copybook.getValue().getItem();
for (Item item : items) {
    Code.printItem(" ", item);
}

并打印 Cobol-Item Code.java:

public static void printItem(String indent, Item item) {
    char[] nc = new char[Math.max(1, 50 - indent.length()
                                        - item.getName().length())];
    String picture = item.getPicture();
    Arrays.fill(nc, ' ');
    if (picture == null) {
        picture = "";
    }
    System.out.println(indent + item.getLevel() + " " + item.getName() 
              + new String(nc) + item.getPosition()
              + " " + item.getStorageLength() + "\t" + picture);
    List<Item> childItems = item.getItem();
    for (Item child : childItems) {
        printItem(indent + " ", child);
    }
} 

Demo2 的输出类似于(给你级别、字段名称、开始、长度和图片):

   01 CompFields                                     1 5099 
      03 NumA                                        1 25   --,---,---,---,---,--9.99
      03 NumB                                        26 3   9V99
      03 NumC                                        29 3   999
      03 text                                        32 20  x(20)
      03 NumD                                        52 3   VPPP999
      03 NumE                                        55 3   999PPP
      03 float                                       58 4   
      03 double                                      62 8   
      03 filler                                      70 23  
         05 RBI-REPETITIVE-AREA                      70 13  
            10 RBI-REPEAT                            70 13  
               15 RBI-NUMBER-S96SLS                  70 7   S9(06)
               15 RBI-NUMBER-S96DISP                 77 6   S9(06)
         05 SFIELD-SEP                               83 10  S9(7)V99

另一个 cb2xml 示例是 DemoCobolJTreeTable.java,它在树 table 中显示 COBOL 字帖: