簡體   English   中英

分割為特殊的非空格空格字符

[英]Split on special non-space whitespace character

我正在使用如下所示的日志文件:

98.87.115.89 - - [12/Nov/2014:05:21:26 -0500] "GET /no_cache/bi_page?Log=1&pg_inst=600474500174606089&pg=mdot_fyc_pnt&platform=mdot&ver=10.c110&pid=157876860906745096&rid=157876731027276387&srch_id=-2&row=7&seq=1&tot=1&tsp=1&test_name=m_control&logDomain=http%3A%2F%2Fwww.xyz.com&ref_url=http%3A%2F%2Fm.xyz.com%2F&z=44134 HTTP/1.1" 200 43 "http://m.xyz.com/" "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; SPH-L720 Build/KOT49H) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16" "98.87.115.89.1415786359690989" web79011

數據看起來像是用SPACE分隔的,但實際上要復雜得多,因為GET之后和最后一行中都有空格,例如在Mobile和Safari之間,即使兩個單詞都是同一元素的一部分。

當我將其粘貼到Excel並在空格上運行TextToColumns時(我不確定我的瀏覽器是否將此特殊字符轉換為普通空格,因此您必須對此表示信任),我得到了以下完美的分割:

98.87.115.89|-|-|[12/Nov/2014:05:21:26 -0500]|"GET /no_cache/bi_page?Log=1&pg_inst=600474500174606089&pg=mdot_fyc_pnt&platform=mdot&ver=10.c110&pid=157876860906745096&rid=157876731027276387&srch_id=-2&row=7&seq=1&tot=1&tsp=1&test_name=m_control&logDomain=http%3A%2F%2Fwww.xyz.com&ref_url=http%3A%2F%2Fm.xyz.com%2F&z=44134 HTTP/1.1"|200|43|"http://m.xyz.com/"|"Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; SPH-L720 Build/KOT49H) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16" "98.87.115.89.1415786359690989"|web79011

請注意,GET和Mobile之后的空白字符不會被用作分隔符。 因此,這意味着正在使用其他一些空白字符。

但是,當我將文本粘貼到Scala(在這里也可以使用Java回答)並使用常規空間運行.split(“”)時,它將所有空白視為一個空間,這會引起很多問題。

如何找出正在使用的特殊字符,如何僅在空格而不是特殊字符上分割?

我認為您最好的選擇是使用正則表達式來執行此操作。 這是我發現有用的參考鏈接: http : //www.tutorialspoint.com/scala/scala_regular_expressions.htm

根據您的示例字符串,這可能是一種嘗試的模式

import scala.util.matching.Regex

 [...]
val str = [... your string to be matched ...]
val pattern1 = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})(?:.*)(\\[.*\])(?:.*?)(\".+?\")(?:.*?)(\\d+)(?:\\s)(\\d+)(?:\\s)(\".+?\")(?:.*?)(\".+?\")(?:.*?)(\".+?\")(.*)".r

尤其是:

(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})  -> matches the IP address
(\\[.*\])                                    -> matches the date and time
(?:.*?)                                      -> matches the bare minimum number of
                                                characters between surrounding patterns
                                                groups
(\".+?\")                                    -> matches the parts between quotes

當然,上述模式具有很幼稚的結構,您可以通過使用重復標記並更仔細地選擇一些組來改進它,但是它應該可以為您提供的樣本完成工作。

設置好圖案后,您可以..

val newstring = (pattern findAllIn str).mkString("|")

請注意,我是用心寫的,因為目前我沒有機會檢查scala中的代碼,但我希望它能提示您使用一個完整的解決方案。

編輯:

在我看來,您的最后一個需求就是不要讓字符串之間用“ |”分隔 而是將所有匹配項作為變量訪問。 在scala中,您可以匹配模式並輕松實現此目的:

val pattern(ip, date, getString, p1, p2, q1, q2, q3) = str

將在ip存儲第一個組的匹配項,在第二個組中存儲date ,依此類推。 括號內的所有參數都是變量,可用於訪問組匹配的內容。 當心那些將是字符串,因此您可能需要為數字強制轉換正確的類型。

Excel的數據導入解析器足夠聰明,可以跳過引號之間的空格。

有多種表達空格的方法,因為Unicode引入了一些新的空格。

我建議使用

\s+ //(normal whitespcaes, pre unicode)

要么

\p{Z}+ //\p{Separator} which would match all Separator, even the ones introduced by unicode)

帶有正則表達式

您可以反過來思考您所需要的內容,並在否定條件下進行拆分,即可以在正則表達式中表示為的每個非whitspace字符

[^\w] or [\W]

不幸的是,這比String.split要復雜得多,因為您想跳過雙引號內的空格。 您可能要使用許多標准解析器,例如apache的CSVParser 或者,如果您不關心諸如用雙引號引起的字段中的轉義雙引號之類的特殊情況,則可能會發生類似的事情(我想不出一種用慣用的scala編寫此方法的方法……很高興看到如果有人提出來一個):

StringTokenizer tokens = new StringTokenizer(inputString, " \"", true);
List<String> fields = new ArrayList<String>(tokens.length);
boolean inquotes = false;
while(tokens.hasMoreTokens()) {
    String tok = tokens.nextToken();   
    if(tok == "\"") {
        inquotes = !inquotes;
        continue;
    }
    if(tok == " " && !inquotes) continue;
    fields.add(tok)
}
String result[] = fields.toArray(new String[fields.size()]); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM