在Java中使用空格对字符串进行分词

9

我想对像这样的字符串进行分词

String line = "a=b c='123 456' d=777 e='uij yyy'";

我无法按照这样的方式进行拆分。
String [] words = line.split(" ");

您好,有什么办法可以将文本分割成如下的标记:

a=b
c='123 456'
d=777
e='uij yyy';  

你不能只使用正则表达式来按空格分割字符串,除非你在引号内(虽然我不知道正则表达式,但我很确定你可以这样做)。 - mk12
你的代码在这里使用jdk 1.6.0_13完美运行。 - Pierre-Adrien
@LePad 上面的代码将输出: [a=b, c='123, 456', d=777, e='uij, yyy'] - Rakesh Juyal
11个回答

9

最简单的方法是手动实现一个简单的有限状态机。换句话说,逐个字符处理字符串:

  • 当遇到空格时,断开一个标记;
  • 当遇到引号时,继续获取字符直到再次遇到引号。

1
有限状态机等同于正则表达式,所以你可以直接使用它,对吧? - Ehtesh Choudhury
1
请注意,您可能需要处理转义引号,例如 "。 - jhclark

3
line.split(" (?=[a-z+]=)")

正确的结果应该是:

a=b
c='123 456'
d=777
e='uij yyy'

请确保在您的键结构更改时适应[a-z+]部分。

编辑:如果键值对中的值部分存在"="字符,则此解决方案可能会失败。


3
根据您原始字符串的格式,您应该能够将正则表达式作为java "split"方法的参数使用:点击此处查看示例。但是该示例并未使用您需要的正则表达式。
您也可以使用此 SO 线程作为指南(尽管它是 PHP),该线程执行与您所需非常接近的操作。稍微调整一下可能就行了(尽管引号是否成为输出的一部分可能会导致一些问题)。请记住,大多数语言中的正则表达式非常相似。 编辑:进一步处理此类型的任务可能超出了正则表达式的能力,因此您可能需要创建一个简单的解析器。

1

StreamTokenizer可以帮助,虽然最容易的设置是在'='处断开,因为它总是会在引号字符串的开头断开:

String s = "Ta=b c='123 456' d=777 e='uij yyy'";
StreamTokenizer st = new StreamTokenizer(new StringReader(s));
st.ordinaryChars('0', '9');
st.wordChars('0', '9');
while (st.nextToken() != StreamTokenizer.TT_EOF) {
    switch (st.ttype) {
    case StreamTokenizer.TT_NUMBER:
        System.out.println(st.nval);
        break;
    case StreamTokenizer.TT_WORD:
        System.out.println(st.sval);
        break;
    case '=':
        System.out.println("=");
        break;
    default:
        System.out.println(st.sval);
    }
}

输出

Ta
=
b
c
=
123 456
d
=
777
e
=
uij yyy

如果您省略掉将数字字符转换为字母的两行代码,那么您将得到d=777.0,这可能对您有用。

1

假设:

  • 你的变量名(在赋值“a=b”中的“a”)可以是长度为1或更多
  • 你的变量名(在赋值“a=b”中的“a”)不能包含空格字符,其他任何字符都可以。
  • 不需要验证输入的有效性(假定输入格式为有效的a=b格式)

这对我来说很好用。

输入:

a=b abc='123 456' &=777 #='uij yyy' ABC='slk slk'              123sdkljhSDFjflsakd@*#&=456sldSLKD)#(

输出:

a=b
abc='123 456'
&=777
#='uij yyy'
ABC='slk slk'             
123sdkljhSDFjflsakd@*#&=456sldSLKD)#(

代码:

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTest {

    // SPACE CHARACTER                                          followed by
    // sequence of non-space characters of 1 or more            followed by
    // first occuring EQUALS CHARACTER       
    final static String regex = " [^ ]+?=";


    // static pattern defined outside so that you don't have to compile it 
    // for each method call
    static final Pattern p = Pattern.compile(regex);

    public static List<String> tokenize(String input, Pattern p){
        input = input.trim(); // this is important for "last token case"
                                // see end of method
        Matcher m = p.matcher(input);
        ArrayList<String> tokens = new ArrayList<String>();
        int beginIndex=0;
        while(m.find()){
            int endIndex = m.start();
            tokens.add(input.substring(beginIndex, endIndex));
            beginIndex = endIndex+1;
        }

        // LAST TOKEN CASE
        //add last token
        tokens.add(input.substring(beginIndex));

        return tokens;
    }

    private static void println(List<String> tokens) {
        for(String token:tokens){
            System.out.println(token);
        }
    }


    public static void main(String args[]){
        String test = "a=b " +
                "abc='123 456' " +
                "&=777 " +
                "#='uij yyy' " +
                "ABC='slk slk'              " +
                "123sdkljhSDFjflsakd@*#&=456sldSLKD)#(";
        List<String> tokens = RegexTest.tokenize(test, p);
        println(tokens);
    }
}

1

或者,使用正则表达式进行标记化,并使用一个小状态机将键/值添加到映射中:

String line = "a = b c='123 456' d=777 e =  'uij yyy'";
Map<String,String> keyval = new HashMap<String,String>();
String state = "key";
Matcher m = Pattern.compile("(=|'[^']*?'|[^\\s=]+)").matcher(line);
String key = null;
while (m.find()) {
    String found = m.group();
    if (state.equals("key")) {
        if (found.equals("=") || found.startsWith("'"))
            { System.err.println ("ERROR"); }
        else { key = found; state = "equals"; }
    } else if (state.equals("equals")) {
        if (! found.equals("=")) { System.err.println ("ERROR"); }
        else { state = "value"; }
    } else if (state.equals("value")) {
        if (key == null) { System.err.println ("ERROR"); }
        else {
            if (found.startsWith("'"))
                found = found.substring(1,found.length()-1);
            keyval.put (key, found);
            key = null;
            state = "key";
        }
    }
}
if (! state.equals("key"))  { System.err.println ("ERROR"); }
System.out.println ("map: " + keyval);

打印输出
map: {d=777, e=uij yyy, c=123 456, a=b}

它进行了一些基本的错误检查,并将值中的引号去除。

0

这个解决方案既通用又紧凑(实际上是cletus答案的正则表达式版本):

String line = "a=b c='123 456' d=777 e='uij yyy'";
Matcher m = Pattern.compile("('[^']*?'|\\S)+").matcher(line);
while (m.find()) {
  System.out.println(m.group()); // or whatever you want to do
}

换句话说,查找由引号括起的字符串或非空字符组合而成的所有字符序列;不支持嵌套引号(即没有转义字符)。

0
public static void main(String[] args) {
String token;
String value="";
HashMap<String, String> attributes = new HashMap<String, String>();
String line = "a=b c='123  456' d=777 e='uij yyy'";
StringTokenizer tokenizer = new StringTokenizer(line," ");
while(tokenizer.hasMoreTokens()){
        token = tokenizer.nextToken();
    value = token.contains("'") ? value + " " + token : token ;
    if(!value.contains("'") || value.endsWith("'")) {
           //Split the strings and get variables into hashmap 
           attributes.put(value.split("=")[0].trim(),value.split("=")[1]);
           value ="";
    }
}
    System.out.println(attributes);
}

输出: {d=777,a=b,e='uij yyy',c='123 456'}

在这种情况下,值中的连续空格将被截断为单个空格。 此处属性哈希映射包含这些值


0
 import java.io.*;
 import java.util.Scanner;

 public class ScanXan {
  public static void main(String[] args) throws IOException {

    Scanner s = null;

    try {
        s = new Scanner(new BufferedReader(new FileReader("<file name>")));

        while (s.hasNext()) {
            System.out.println(s.next());
           <write for output file>
        }
    } finally {
        if (s != null) {
            s.close();
        }
    }
 }
}

是的 @YoungHobbit,我的工作环境是Linux(Ubuntu 15.01),使用Sublime3编码。 - jsingh

-1
java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(line, " ");
while (tokenizer.hasMoreTokens()) {
    String token = tokenizer.nextToken();
    int index = token.indexOf('=');
    String key = token.substring(0, index);
    String value = token.substring(index + 1);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接