2013-08-01 74 views
2

當我輸入這樣的:如何將字符串轉換爲Python中的令牌列表?

>>>tokenize('<[2{12.5 6.0}](3 -4 5)>') 

我想這回:

['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 

基本上,我將如何保持它使輸入的一切轉換成列表,同時保持數字原來的值。

+0

這是一個很好的問題。 – zsong

+0

你在找Python中的lex工具嗎?你可以試試PLY http://www.dabeaz.com/ply/。 – neuront

+0

將字符串拆分爲單個字符的列表。迭代列表一次,將類似數字的字符(數字,句點,連字符)組合在一起。再次遍歷列表,將塊轉換爲整數或浮點數。你完成了。 – misha

回答

-2

所以這是一個與蟒蛇一個非常好的解決方案

list(my_string)做了標記化開始,但不會保留你喜歡的特性:(。

所以對於我們可以的,如果我們要使用一些比必要的機械

import re 
a = '<[2{12.5 6.0}](3 -4 5)>' 
tokenized = [x in re.split(r'[[!"#$%&\'()*+,\-/:;<=>[email protected][\\\]^_`{|}~ ]]*',a)) if x!=''] 
#or also 
tokens = [x in re.split(r'[[!"#$%&\'()*+,\-/:;<=>[email protected][\\\]^_`{|}~ ]]*',a)) if x] 

這可以用任何語言/白板表達式中使用和標點符號距離strings.punctuation稍重,你可以自定義來界定上東西可以用正則表達式來表達 - 這幾乎是一切。

使用re.compile預編譯表達式,如果你正在一個巨大的字符串上運行它 - 你會得到更好的優化。在某些限制條件下,你也可以使用自動機;),這給了MASSIVE的好處

+0

當然不是..(但我沒有投票:)) – zsong

+0

他想保持數字的原始價值。如果你做了list(),那麼你也將數字標記爲數字。請嘗試。 – zsong

+0

它確實將它們添加到列表中。但是,它打破了整個數字。我希望12.5保持爲[12.5,6.0]。不是['1','2','。','5'] –

0

因此,蠻力,你可以使用list(your_string),但一定要確定什麼應該組合在一起,附加項目隨着你去的元素。

其他解決方案可以有正則表達式,簡單的語法庫等,並且可以說是更容易理解。

編輯:對於非整數#s,你也可以注意到當遇到這樣一個數字時,繼續並改變新的解析的標記列表的前一個索引,當你到達下一個數字時,關閉,令牌等,你會在列表中創建一個全新的元素。

假設你把一切都變成新的列表作爲字符串,這裏是讓你的花車&整數後面的一個方式:

for i, e in enumerate(tokenized): 
    if e.isdigit(): 
     tokenized[i] = int(e) 
    elif '.' in e: 
     tokenized[i] = float(e) 
    elif '-' in e and not '.' in e: 
     tokenized[i] = int(e) 

最終的結果是你想要什麼:

['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 
+0

此外,該輸入是否應該針對問題的輸入建模?它可以更長嗎?更先進?它是否始終以'<'開頭並以'>'結尾? – jheld

0

re.split可能是你想要的。查看similar question here

將字符串拆分爲列表後,可以遍歷它並使用int()float()將數字成員轉換爲實際數字。

1

您可以嘗試使用tokenizer,除了像-4這樣的負數,它會給出與預期幾乎相同的結果,但它非常接近。

from StringIO import StringIO 
import tokenize 
str = '<[2{12.5 6.0}](3 -4 5)>' 
tokens = tokenize.generate_tokens(StringIO(str).readline) 
result = [x[1] for x in tokens] 

下面是結果:

['[', '2', '{', '12.5', '6.0', '}', ']', '(', '3', '-', '4', '5', ')', '>', ''] 
+0

不錯,但令牌特定於Python,不可配置。 –

0

一個PLY解決

tokens = (
    'LT', 'GT', 'LPAREN', 'RPAREN', 'LBRACKET', 'RBRACKET', 'LBRACE', 'RBRACE', 
    'FLOAT', 'INTEGER', 
) 

t_LT = r'<' 
t_GT = r'>' 
t_LPAREN = r'\(' 
t_RPAREN = r'\)' 
t_LBRACKET = r'\[' 
t_RBRACKET = r'\]' 
t_LBRACE = r'{' 
t_RBRACE = r'}' 
t_ignore = r' ' 

def t_FLOAT(t): 
    r'-?\d*[.]\d+' 
    t.value = float(t.value) 
    return t 

def t_INTEGER(t): 
    r'-?\d+' 
    t.value = int(t.value) 
    return t 

def t_error(t): 
    raise ValueError('invalid input') 

import ply.lex as lex 
lex.lex() 

lex.input('<[2{12.5 6.0}](3 -4 5)>') 
tokens = list(iter(lex.token, None)) 
for t in tokens: 
    print repr(t.type), repr(t.value) 
print '>', [t.value for t in tokens] 

輸出:

'LT' '<' 
'LBRACKET' '[' 
'INTEGER' 2 
'LBRACE' '{' 
'FLOAT' 12.5 
'FLOAT' 6.0 
'RBRACE' '}' 
'RBRACKET' ']' 
'LPAREN' '(' 
'INTEGER' 3 
'INTEGER' -4 
'INTEGER' 5 
'RPAREN' ')' 
'GT' '>' 
> ['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 

您需要安裝PLY。要安裝它,只需

# pip install ply 
0
import re 

s = '<[2{12.5 6.0}](3 -4 5)>' 
p = re.compile(r"([-+]?(?:(?:\d*\.\d+)|(?:\d+\.?)))|(\S)") 

conv = lambda n: float(n) if '.' in n else int(n) 

[conv(m.group(1)) if m.lastindex==1 else m.group(2) for m in p.finditer(s)] 

出來:

['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 
+0

非常感謝! –

0
import re 

def tokenize(txt): 

    output = [] 

    tokenized = re.split('([\<\>\[\]\{\}\(\)\s])',txt) 

    for t in tokenized: 
     if len(t.strip()) > 0: 
      if re.match("^\d+?\.\d+?$",t) is None: 
       if re.match("^[\d\-]\d*?$",t) is None: 
        output.append(t) 
       else: 
        output.append(int(t)) 
      else: 
       output.append(float(t)) 

    print(output) 


tokenize('<[2{12.5 6.0}](3 -4 5)>') 

和輸出:

['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 
0

下面的方法只使用正則表達式

import re 
def tokenize(your_string): 
    pattern = re.compile(r'([-+]?[0-9]*\.?[0-9]+)') # float pattern 
    digital = re.compile(r'([-+]?[0-9]*$)') 
    lst = [] 
    for item in pattern.split(your_string): 
     if not item.isspace(): # remove space 
      if pattern.match(item): 
       if digital.match(item): 
        lst.append(int(item)) 
       else: 
        lst.append(float(item)) # change string to float 
      else: 
       lst.extend(list(item)) # make unmatched string to character list 
    return lst 

print tokenize('<[2{12.5 6.0}](3 -4 5)>') 

,其結果是

['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 
0

我最喜歡爲這樣的事情工具pyparsing

from pyparsing import Word, ZeroOrMore, oneOf, nums 

def tokenize(s): 
    number = Word(nums + '.' + '-') 
    number.setParseAction(lambda x : eval(x[0])) 
    punctuation = '< > [ ] () { }' 
    lexeme = number | oneOf(punctuation) | ' ' 
    tokenizer = ZeroOrMore(lexeme) 

    return tokenizer.parseString(s) 


print tokenize('<[2{12.5 6.0}](3 -4 5)>') 

輸出:

['<', '[', 2, '{', 12.5, 6.0, '}', ']', '(', 3, -4, 5, ')', '>'] 

與PLY,你可以用pip install pyparsing安裝(你可以安裝帶有easy_install pip點子,如果你沒有的話)。同樣在實際使用中,您可能不希望每次調用都創建pyparsing對象,因此它們可能是全局的,等等。

+0

另外,提示:將oneOf(標點符號)更改爲Suppress(oneOf(標點符號))會給出輸出[2,12.5,6。0,3,-4,5] – johncip

相關問題