Ver código fonte

Updated str.format to tokenization-based-replacement operation

S. Mahmudul Hasan 2 anos atrás
pai
commit
ee54816421
1 arquivos alterados com 104 adições e 13 exclusões
  1. 104 13
      python/builtins.py

+ 104 - 13
python/builtins.py

@@ -96,21 +96,112 @@ def sorted(iterable, reverse=False, key=None):
     return a
 
 ##### str #####
-def __f(self, *args, **kwargs):
-    if '{}' in self:
-        for i in range(len(args)):
-            self = self.replace('{}', str(args[i]), 1)
-    else:
-        # Positional arguments will be followed by keyword arguments
-        # 1. Replace the positional arguments
-        for i,a in enumerate(args):
-            self = self.replace('{'+str(i)+'}', str(a))
+def tokenize(s:str) -> list:
+    tokens = []
+    L, R = 0,0
+    
+    mode = None
+    curPos = 0
+    lookingForKword = False
+    
+    while(R<len(s) and not lookingForKword):
+        curChar = s[R]
+        nextChar = s[R+1] if R+1<len(s) else ''
+        
+        # Escaping case
+        if (curChar == '{' and nextChar == '{') or (curChar == '}' and nextChar == '}'):
+            tokens.append(curChar)
+            L = R+2
+            R = R+2
+            continue
+        
+        # Regular command line arg case
+        if curChar == '{' and nextChar == '}':
+            
+            if mode is not None and mode != 'auto':
+                raise ValueError("Cannot switch from manual field numbering to automatic field specification")
+            
+            mode = 'auto'
+            # best case {}, just for normal args
+            if(L<R):
+                tokens.append(s[L:R])
+            tokens.append("{"+str(curPos)+"}")
+            curPos+=1
+            L = R+2
+            R = R+2
+            continue
+        
+        # Kwarg case
+        elif (curChar == '{'):
+            
+            if mode is not None and mode != 'manual':
+                raise ValueError("Cannot switch from automatic field specification to manual field numbering")
+            
+            mode = 'manual'
+            
+            if(L<R):
+                tokens.append(s[L:R])
+            
+            lookingForKword = True
+            kwL = R+1
+            kwR = R+1
+            while(kwR<len(s) and s[kwR]!='}'):
+                kwR += 1
+            tokens.append(s[R:kwR+1])
+            
+            if kwR<len(s) and s[kwR] == '}':
+                lookingForKword = False
+                L = kwR+1
+                R = kwR+1
+            continue
+        
+        R = R+1
+    
+    if lookingForKword:
+        raise ValueError("Expected '}' before end of string")
+    
+    if(not lookingForKword and L<R):
+        tokens.append(s[L:R])
+
+    # print("Looking for kword: ", lookingForKword)
+    return tokens
+def __f(self:str, *args, **kwargs) -> str:
+    tokens = tokenize(self)
+    argMap = {}
+    for i, a in enumerate(args):
+        argMap[str(i)] = a
+    final_tokens = []
+    for t in tokens:
+        if t[0] == '{' and t[-1] == '}':
+            key = t[1:-1]
+            argMapVal = argMap.get(key, None)
+            kwargsVal = kwargs.get(key, None)
+            
+            if argMapVal is None and kwargsVal is None:
+                raise ValueError("No arg found for token: "+t)
+            elif argMapVal is not None:
+                final_tokens.append(str(argMapVal))
+            else:
+                final_tokens.append(str(kwargsVal))
+        else:
+            final_tokens.append(t)
+    
+    return ''.join(final_tokens)
+ 
+    # if '{}' in self:
+    #     for i in range(len(args)):
+    #         self = self.replace('{}', str(args[i]), 1)
+    # else:
+    #     # Positional arguments will be followed by keyword arguments
+    #     # 1. Replace the positional arguments
+    #     for i,a in enumerate(args):
+    #         self = self.replace('{'+str(i)+'}', str(a))
         
-        # 2. Replace the keyword arguments
-        for k,v in kwargs.items():
-            self = self.replace('{'+k+'}', str(v))
+    #     # 2. Replace the keyword arguments
+    #     for k,v in kwargs.items():
+    #         self = self.replace('{'+k+'}', str(v))
     
-    return self
+    # return self
 str.format = __f
 
 def __f(self, chars=None):