2009-10-01 25 views
9

Tôi muốn tokenize một chuỗi như thế nàytokenize một chuỗi với một không gian trong java

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

tôi không thể chia nhỏ các căn cứ như thế này

String [] words = line.split(" "); 

ý tưởng Bất kỳ làm thế nào tôi có thể chia vì vậy mà tôi có được thẻ như

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

Bạn không thể sử dụng regex để chia nhỏ khoảng trắng trừ khi bạn đang ở trong một báo giá (không phải là tôi biết regex, nhưng tôi khá chắc chắn bạn có thể làm điều đó). – mk12

+0

Mã của bạn hoàn toàn hoạt động ở đây bằng cách sử dụng jdk 1.6.0_13 –

+0

@LePad mã trên sẽ xuất ra * [a = b, c = '123, 456', d = 777, e = 'uij, yyy'] * –

Trả lời

9

Cách đơn giản nhất để thực hiện việc này là thực hiện bằng tay một máy trạng thái hữu hạn đơn giản. Nói cách khác, xử lý chuỗi một ký tự tại một thời điểm:

  • Khi bạn nhấn vào một dấu cách, hãy ngắt mã thông báo;
  • Khi bạn nhấn dấu ngoặc kép, hãy tiếp tục nhận các ký tự cho đến khi bạn nhấn một dấu trích dẫn khác.
+1

Trạng thái hữu hạn máy tương đương với biểu thức chính quy, vì vậy bạn chỉ có thể gắn bó với điều đó, đúng không? –

+1

Hãy coi chừng rằng bạn có thể cần phải xử lý các dấu ngoặc kép thoát như \ " – jhclark

3

Tùy thuộc vào định dạng của chuỗi ban đầu, bạn sẽ có thể sử dụng biểu thức chính quy làm tham số cho phương thức "tách" java: Click here for an example.

Ví dụ này không sử dụng cụm từ thông dụng mà bạn sẽ cần cho tác vụ này.

Bạn cũng có thể sử dụng this SO thread làm hướng dẫn (mặc dù nó bằng PHP) thực hiện điều gì đó rất gần với những gì bạn cần. Thao tác mà hơi có thể làm các trick (mặc dù có dấu ngoặc kép là một phần của đầu ra hay không có thể gây ra một số vấn đề). Hãy nhớ rằng regex rất giống nhau trong hầu hết các ngôn ngữ.

Chỉnh sửa: tiến xa hơn nữa vào loại tác vụ này có thể đi trước khả năng của regex, vì vậy bạn có thể cần tạo trình phân tích cú pháp đơn giản.

-2

Bạn đã thử tách bằng '=' và tạo mã thông báo ra khỏi mỗi cặp của mảng kết quả chưa?

+0

Điều này có cùng vấn đề với giải pháp .split() được đề cập trong câu hỏi. –

+0

@rajax Giải pháp này không hiệu quả, nhưng bạn có thể làm một việc như chia nhỏ một không gian, sau đó đi qua từng chuỗi phân tách: nếu nó bắt đầu bằng '(giả sử nó được định dạng tốt), thì bạn chỉ cần nối các chuỗi này lại với nhau cho đến khi bạn tìm thấy chuỗi kết thúc bằng'. Tokenziers Chuỗi hoặc máy trạng thái (hoặc sử dụng ngăn xếp nếu bạn muốn cho phép nhiều cấp độ báo giá lồng nhau bằng cách xen kẽ các loại trích dẫn ala python) có thể hiệu quả hơn, nhưng điều này cũng có thể hoạt động! – DivineWolfwood

1

StreamTokenizer có thể giúp đỡ, mặc dù nó là dễ nhất để thiết lập để phá vỡ trên '=', vì nó sẽ luôn luôn phá vỡ vào lúc bắt đầu của một chuỗi trích dẫn:

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); 
    } 
} 

đầu ra

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

Nếu bạn bỏ qua hai dòng chuyển đổi các ký tự số thành alpha, thì bạn sẽ nhận được d=777.0, điều này có thể hữu ích cho bạn.

-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); 
} 
+0

Điều này sẽ không hoạt động đối với chuỗi mẫu – user101884

+0

Bạn nói đúng. –

1

Giả định:

  • tên biến của bạn ('a' trong chuyển nhượng 'a = b') có thể có độ dài 1 hoặc nhiều
  • tên biến của bạn ('a' trong nhiệm vụ 'a = b') không thể chứa ký tự khoảng trắng, bất cứ điều gì khác đều tốt.
  • Xác nhận của đầu vào của bạn không được yêu cầu (đầu vào giả định là trong một định dạng = b hợp lệ)

này hoạt động tốt đối với tôi.

Input:

a=b abc='123 456' &=777 #='uij yyy' ABC='slk slk'    [email protected]*#&=456sldSLKD)#(

Output:

a=b 
abc='123 456' 
&=777 
#='uij yyy' 
ABC='slk slk'    
[email protected]*#&=456sldSLKD)#(

Code:

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'    " + 
       "[email protected]*#&=456sldSLKD)#("; 
     List<String> tokens = RegexTest.tokenize(test, p); 
     println(tokens); 
    } 
} 
0

Giải pháp này là cả hai nói chung và nhỏ gọn (nó là một cách hiệu quả các phiên bản regex của câu trả lời 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 
} 

Nói cách khác, hãy tìm tất cả các lần chạy các ký tự là tổ hợp các chuỗi được trích dẫn hoặc các ký tự không dấu cách; dấu ngoặc kép không được hỗ trợ (không có ký tự thoát).

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

cho đúng:

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

Hãy chắc chắn rằng bạn thích ứng với [a-z +] phần trong trường hợp các phím cấu trúc của bạn thay đổi.

Chỉnh sửa: giải pháp này có thể thất bại thảm hại nếu có ký tự "=" trong phần giá trị của cặp.

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); 
} 

đầu ra: {d = 777, a = b, e = 'uij yyy', c = '123 456'}

Trong trường hợp này không gian liên tục sẽ được cắt ngắn để không gian duy nhất trong giá trị. hashmap đây do chứa các giá trị

1

Hoặc, với một regex cho tokenizing, và một máy nhà nước nhỏ mà chỉ bổ sung thêm phím/val vào bản đồ:

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); 

in ra

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

Nó thực hiện một số kiểm tra lỗi cơ bản, và trích dẫn các giá trị.

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(); 
     } 
    } 
} 
} 
+0

Bạn đã kiểm tra mã này chưa? – YoungHobbit

+0

Có @YoungHobbit Môi trường làm việc của tôi Linux (Ubuntu 15.01) được mã hóa trên sublime3. – jsroyal

Các vấn đề liên quan