如何从字符串中分离许多不同的单词(Java)

时间:2018-12-20 21:17:29

标签: java arrays string indexing substring

我一直在努力找出如何从文件中读取长度未知的字符串来获取长度未知的单词。我要从字符串中得到的单词始终以“。”分隔。和/或“&”,整个字符串用引号引起来。例如:“。Word.Characters&Numeric&Letters.Typos&Mistypes。”我知道每个“。”的位置。和“&”,以及它们出现了多少次。

我想根据单词是否用“。”分隔,将单词输入到数组Example [i] [j]中。或“&”。因此在“。”之间包含单词。将设置为数组的第i列,将由“&”链接的单词设置为数组的第j行。

输入字符串可以包含数量变化很大的单词。意思是只有一个感兴趣的词,或者一百多个。

我更喜欢使用数组来解决这个问题。从我读过的正则表达式会很慢,但工作。 split()也许也可以,但是我想我必须先知道要寻找什么词。

从此字符串开始:“。Word.Characters&Numeric&Letters.Typos&Mistypes。”我希望得到:(无需担心是行还是列)

[[Word],[null],[null]],

[[字符],[数字],[字母]],

[[Typos],[Mistypes],[null]]

从此字符串“ .Alpha.Beta.Zeta&Iota”开始。我希望得到:

[[[Alpha],[null]],

[[Beta],[null]],

[[Zeta],[Iota]]

//NumerOfPeriods tells me how many word "sections" are in the string
//Stor[] is an array that holds the string index locations of "."
for(int i=0;i<NumberOfPeriods;i++)
{
    int length = Stor[i];
    while(Line.charAt(length) != '"')
    {
        length++;
    }
    Example[i] = Line.substring(Stor[i], length);
}
//This code can get the words separated by "." but not by "&"

//Stor[] is an array that holds all string index locations of '.'
//AmpStor[] is an array that holds all string index locations of '&'
int TotalLength = Stor[0];
int InnerLength = 0;
int OuterLength = 0;
while(Line.charAt(TotalLength) != '"')
{
    while(Line.charAt(OuterLength)!='.')
    {
        while(Line.charAt(InnerLength)!='&')
        {
            InnerLength++;
        }
        if(Stor[i] > AmpStor[i])
        {
            Example[i][j] = Line.substring(Stor[i], InnerLength);
        }
        if(Stor[i] < AmpStor[i])
        {
            Example[i][j] = Line.substring(AmpStor[i],InnerLength);
        }
            OuterLength++;
    }
}
//Here I run into the issue of indexing into different parts of the array i & j

3 个答案:

答案 0 :(得分:1)

这就是我解决您的问题的方式(它与您的代码完全不同,但是可以工作)。

首先,删除引号以及开头和结尾的非单词字符。可以使用replaceAll

String Formatted = Line.replaceAll( "(^\"[.&]*)|([.&]*\"$)", "" );

第一个参数中的正则表达式将匹配两端的双引号以及前.和后&的双引号。该方法将返回一个删除了匹配字符的新字符串,因为第二个参数是一个空字符串(它将替换为一个空字符串)。

现在,您可以使用.方法在每个split处拆分此字符串。您只能在此调用之后定义输出数组:

String[] StringGroups = Formatted.split( "\\." );
String[][] Elements = new String[StringGroups.length][];

在该点之前使用转义的反斜杠(\\)表示应在.个字符上进行拆分,因为此方法采用了正则表达式(而.仅对任何非换行符)。

现在使用相同的&方法在每个split处拆分该数组中的每个字符串。将结果直接添加到您的Elements数组中:

// Loop over the array
int MaxLength = 0;
for( int i = 0; i < StringGroups.length; i ++ ) {
   String StrGroup = StringGroups[ i ];
   String[] Group = StrGroup.split( "&" );
   Elements[ i ] = Group;

   // Measure the max length
   if( Group.length > MaxLength ) {
       MaxLength = Group.length;
   }
}

输入\\并不是必需的,因为&仅匹配&个字符。现在,您只需要将数据填写到数组中即可。 MaxLength变量用于将null值添加到您的数组中。如果您不想要它们,只需将其删除,即可完成操作。

但是,如果要使用null值,请遍历elements数组并将当前行复制到新数组中:

for( int i = 0; i < Elements.length; i ++ ) {
    String[] Current = Elements[ i ];
    String[] New = new String[ MaxLength ];

    // Copy existing values into new array, extra values remain null
    System.arraycopy( Current, 0, New, 0, Current.length );
    Elements[ i ] = New;
}

现在,Elements数组完全包含您想要的内容。

这是完整的可执行代码:

public class StringSplitterExample {
    public static void main( String[] args ) {
        test( "\".Word.Characters&Numeric&Letters.Typos&Mistypes.\"" );
        System.out.println(); // Line between
        test( "\".Alpha.Beta.Zeta&Iota.\"" );
    }

    public static void test( String Line ) {
        String Formatted = Line.replaceAll( "(^\"[.&]*)|([.&]*\"$)", "" );
        String[] StringGroups = Formatted.split( "\\." );
        String[][] Elements = new String[StringGroups.length][];

        // Loop over the array
        int MaxLength = 0;
        for( int i = 0; i < StringGroups.length; i ++ ) {
            String StrGroup = StringGroups[ i ];
            String[] Group = StrGroup.split( "&" );
            Elements[ i ] = Group;

            // Measure the max length
            if( Group.length > MaxLength ) {
                MaxLength = Group.length;
            }
        }

        for( int i = 0; i < Elements.length; i ++ ) {
            String[] Current = Elements[ i ];
            String[] New = new String[ MaxLength ];

            // Copy existing values into new array, extra values remain null
            System.arraycopy( Current, 0, New, 0, Current.length );
            Elements[ i ] = New;
        }

        for( String[] Group : Elements ) {
            for( String String : Group ) {
                System.out.print( String );
                System.out.print( " " );
            }
            System.out.println();
        }
    }
}

此示例的输出:

Word null null 
Characters Numeric Letters 
Typos Mistypes null 

Alpha null 
Beta null 
Zeta Iota 

所以这可行,而且您甚至不需要知道字符串中的.&字符。 Java会为您做到这一点。

答案 1 :(得分:1)

如果我正确理解了该问题,则需要将字符串分成以'。'分隔的子字符串。然后对于每个子字符串,将其分成以'&'分隔的子子字符串。如果是这种情况,那么我将使用split方法:

List<List<String>> terms = Arrays.stream(input.split("\\."))
    .map(s -> Arrays.asList(s.split("\\&"))
    .collect(Collectors.toList());

如果您确实需要将其作为填充为null的数组返回:

String[][] result = new String[terms.size()][ terms.stream.mapToInt(List::size).max().getAsInt()];
IntStream.range(0, terms.size()).forEach(i ->
    IntStream.range(0, terms.get(i).size()).forEach(j -> 
        result[i][j] = terms.get(i).get(j)));

答案 2 :(得分:1)

这是我尝试解决此问题的方法:

import java.util.*;
import java.util.stream.*;

public class StringSplitSplits {

    private static final String S1 = ".Word.Characters&Numeric&Letters.Typos&Mistypes.";
    private static final String S2 = ".Alpha.Beta.Zeta&Iota.";

    public static void main(String [] args) {

        String str = stripStartAndEndDots(S1);
        String [] ss = str.split("\\.");
        int maxLength = getMaxLength(ss);

        String [][] sss = Stream.of(ss)
                                .map(s -> s.split("&"))
                                .map(s -> Arrays.copyOf(s, maxLength))
                                .toArray(String[][]::new);
        Stream.of(sss).forEach(s -> System.out.println(Arrays.toString(s)));
    }

    private static String stripStartAndEndDots(String input) {
        if (input.startsWith(".")) {
            input = input.substring(1);
        }
        if (input.endsWith(".")) {
            input = input.substring(0, input.length()-1);
        }
        return input;
    }

    /*
     * Get max length of the arrays split on the "&" for each
     * string element of the input string array.
     */
    private static int getMaxLength(String [] input) {
        return Stream.of(input)
                        .map(s -> s.split("&"))
                        .mapToInt(ss -> ss.length)
                        .max()
                        .orElse(0);
    }
}


输入:".Word.Characters&Numeric&Letters.Typos&Mistypes."
输出:

[Word, null, null]
[Characters, Numeric, Letters]
[Typos, Mistypes, null]

输入:".Alpha.Beta.Zeta&Iota."
输出:

[Alpha, null]
[Beta, null]
[Zeta, Iota]