Lua에 문자열이 있고 그 안의 개별 문자를 반복하고 싶습니다. 그러나 내가 시도한 코드는 없으며 공식 매뉴얼은 하위 문자열을 찾고 바꾸는 방법 만 보여줍니다.
str = "abcd"
for char in str do -- error
print( char )
end
for i = 1, str:len() do
print( str[ i ] ) -- nil
end
답변
lua 5.1에서는 몇 가지 방법으로 문자열의 문자를 반복 할 수 있습니다.
기본 루프는 다음과 같습니다.
i = 1 인 경우 #str do 로컬 c = str : sub (i, i) -c로 무언가를하십시오 종료
그러나 패턴을 사용 string.gmatch()
하여 문자에 대한 반복자를 얻는 것이 더 효율적일 수 있습니다 .
for c in str : gmatch "." 하다 -c로 무언가를하십시오 종료
또는 string.gsub()
각 문자에 대한 함수를 호출하는 데 사용할 수도 있습니다 .
str : gsub ( ".", function (c) -c로 무언가를하십시오 종료)
위의 모든 과정에서 string
모듈이 모든 문자열 값에 대한 메타 테이블로 설정되어 있으므로 해당 함수를 :
표기법을 사용하여 멤버로 호출 할 수 있다는 사실을 활용 했습니다 . 또한 #
문자열 길이를 얻기 위해 (5.1, IIRC의 새로운 기능)을 사용했습니다 .
애플리케이션에 대한 최선의 답은 많은 요인에 따라 달라지며 성능이 중요하다면 벤치 마크가 친구가됩니다.
문자를 반복해야하는 이유 를 평가 하고 Lua에 바인딩 된 정규식 모듈 중 하나를 살펴 보거나, 현대적인 접근 방식을 위해 Lua에 대한 구문 분석 표현식 그래머를 구현하는 Roberto의 lpeg 모듈을 살펴볼 수 있습니다.
답변
Lua 5를 사용하는 경우 다음을 시도하십시오.
for i = 1, string.len(str) do
print( string.sub(str, i, i) )
end
답변
당면한 작업에 따라 사용하기가 더 쉬울 수 있습니다 string.byte
. 또한 각 새 문자열을 해싱하고 이미 알고 있는지 확인하기 때문에 Lua에서 비용이 많이 드는 새 하위 문자열을 만들지 않기 때문에 가장 빠른 방법입니다. string.byte
가독성과 이식성을 유지하기 위해 찾고있는 기호의 코드를 미리 계산할 수 있습니다 .
local str = "ab/cd/ef"
local target = string.byte("/")
for idx = 1, #str do
if str:byte(idx) == target then
print("Target found at:", idx)
end
end
답변
제공된 답변 ( here , here 및 here ) 에는 이미 많은 좋은 접근 방식이 있습니다 . 속도가 당신이 주로 찾고 있는 것이라면 루아의 C API를 통해 작업을하는 것을 확실히 고려해야합니다. 이것은 원시 Lua 코드보다 몇 배나 빠릅니다. 미리로드 된 청크 (예 : load function )로 작업 할 때 차이는 그다지 크지는 않지만 여전히 상당합니다.
순수한 Lua 솔루션에 대해 제가 만든이 작은 벤치 마크를 공유하겠습니다. 이 날짜에 제공된 모든 답변을 다루고 몇 가지 최적화를 추가합니다. 그래도 고려해야 할 기본 사항은 다음과 같습니다.
문자열의 문자를 몇 번 반복해야합니까?
- 대답이 “한 번”이면 banchmark의 첫 부분 ( “raw speed”)을 찾아야합니다.
- 그렇지 않으면 두 번째 부분은 문자열을 테이블로 구문 분석하여 반복하는 속도가 훨씬 빠르기 때문에 더 정확한 추정을 제공합니다. @Jarriz가 제안한 것과 같은 간단한 함수 작성도 고려해야합니다.
다음은 전체 코드입니다.
-- Setup locals
local str = "Hello World!"
local attempts = 5000000
local reuses = 10 -- For the second part of benchmark: Table values are reused 10 times. Change this according to your needs.
local x, c, elapsed, tbl
-- "Localize" funcs to minimize lookup overhead
local stringbyte, stringchar, stringsub, stringgsub, stringgmatch = string.byte, string.char, string.sub, string.gsub, string.gmatch
print("-----------------------")
print("Raw speed:")
print("-----------------------")
-- Version 1 - string.sub in loop
x = os.clock()
for j = 1, attempts do
for i = 1, #str do
c = stringsub(str, i)
end
end
elapsed = os.clock() - x
print(string.format("V1: elapsed time: %.3f", elapsed))
-- Version 2 - string.gmatch loop
x = os.clock()
for j = 1, attempts do
for c in stringgmatch(str, ".") do end
end
elapsed = os.clock() - x
print(string.format("V2: elapsed time: %.3f", elapsed))
-- Version 3 - string.gsub callback
x = os.clock()
for j = 1, attempts do
stringgsub(str, ".", function(c) end)
end
elapsed = os.clock() - x
print(string.format("V3: elapsed time: %.3f", elapsed))
-- For version 4
local str2table = function(str)
local ret = {}
for i = 1, #str do
ret[i] = stringsub(str, i) -- Note: This is a lot faster than using table.insert
end
return ret
end
-- Version 4 - function str2table
x = os.clock()
for j = 1, attempts do
tbl = str2table(str)
for i = 1, #tbl do -- Note: This type of loop is a lot faster than "pairs" loop.
c = tbl[i]
end
end
elapsed = os.clock() - x
print(string.format("V4: elapsed time: %.3f", elapsed))
-- Version 5 - string.byte
x = os.clock()
for j = 1, attempts do
tbl = {stringbyte(str, 1, #str)} -- Note: This is about 15% faster than calling string.byte for every character.
for i = 1, #tbl do
c = tbl[i] -- Note: produces char codes instead of chars.
end
end
elapsed = os.clock() - x
print(string.format("V5: elapsed time: %.3f", elapsed))
-- Version 5b - string.byte + conversion back to chars
x = os.clock()
for j = 1, attempts do
tbl = {stringbyte(str, 1, #str)} -- Note: This is about 15% faster than calling string.byte for every character.
for i = 1, #tbl do
c = stringchar(tbl[i])
end
end
elapsed = os.clock() - x
print(string.format("V5b: elapsed time: %.3f", elapsed))
print("-----------------------")
print("Creating cache table ("..reuses.." reuses):")
print("-----------------------")
-- Version 1 - string.sub in loop
x = os.clock()
for k = 1, attempts do
tbl = {}
for i = 1, #str do
tbl[i] = stringsub(str, i) -- Note: This is a lot faster than using table.insert
end
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V1: elapsed time: %.3f", elapsed))
-- Version 2 - string.gmatch loop
x = os.clock()
for k = 1, attempts do
tbl = {}
local tblc = 1 -- Note: This is faster than table.insert
for c in stringgmatch(str, ".") do
tbl[tblc] = c
tblc = tblc + 1
end
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V2: elapsed time: %.3f", elapsed))
-- Version 3 - string.gsub callback
x = os.clock()
for k = 1, attempts do
tbl = {}
local tblc = 1 -- Note: This is faster than table.insert
stringgsub(str, ".", function(c)
tbl[tblc] = c
tblc = tblc + 1
end)
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V3: elapsed time: %.3f", elapsed))
-- Version 4 - str2table func before loop
x = os.clock()
for k = 1, attempts do
tbl = str2table(str)
for j = 1, reuses do
for i = 1, #tbl do -- Note: This type of loop is a lot faster than "pairs" loop.
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V4: elapsed time: %.3f", elapsed))
-- Version 5 - string.byte to create table
x = os.clock()
for k = 1, attempts do
tbl = {stringbyte(str,1,#str)}
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V5: elapsed time: %.3f", elapsed))
-- Version 5b - string.byte to create table + string.char loop to convert bytes to chars
x = os.clock()
for k = 1, attempts do
tbl = {stringbyte(str, 1, #str)}
for i = 1, #tbl do
tbl[i] = stringchar(tbl[i])
end
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V5b: elapsed time: %.3f", elapsed))
출력 예 (Lua 5.3.4, Windows) :
-----------------------
Raw speed:
-----------------------
V1: elapsed time: 3.713
V2: elapsed time: 5.089
V3: elapsed time: 5.222
V4: elapsed time: 4.066
V5: elapsed time: 2.627
V5b: elapsed time: 3.627
-----------------------
Creating cache table (10 reuses):
-----------------------
V1: elapsed time: 20.381
V2: elapsed time: 23.913
V3: elapsed time: 25.221
V4: elapsed time: 20.551
V5: elapsed time: 13.473
V5b: elapsed time: 18.046
결과:
내 경우, string.byte
그리고 string.sub
원시 속도면에서 빠른했다. 캐시 테이블을 사용하고 루프 당 10 번 재사용하면 string.byte
문자 코드를 문자로 다시 변환 할 때도 버전이 가장 빠릅니다 (항상 필요한 것은 아니며 사용량에 따라 다름).
아시다시피 이전 벤치 마크를 기반으로 몇 가지 가정을하고이를 코드에 적용했습니다.
- 라이브러리 함수는 훨씬 더 빠르기 때문에 루프 내에서 사용되는 경우 항상 지역화되어야합니다.
- lua 테이블에 새 요소를 삽입하는 것은를 사용하는
tbl[idx] = value
것보다 훨씬 빠릅니다table.insert(tbl, value)
. - 를 사용하여 테이블을 반복
for i = 1, #tbl
하는 것이for k, v in pairs(tbl)
. - 호출 자체가 실행 시간을 약간 추가하기 때문에 항상 함수 호출이 적은 버전을 선호합니다.
도움이 되었기를 바랍니다.
답변
모든 사람들은 덜 최적의 방법을 제안합니다
최선일 것 :
function chars(str)
strc = {}
for i = 1, #str do
table.insert(strc, string.sub(str, i, i))
end
return strc
end
str = "Hello world!"
char = chars(str)
print("Char 2: "..char[2]) -- prints the char 'e'
print("-------------------\n")
for i = 1, #str do -- testing printing all the chars
if (char[i] == " ") then
print("Char "..i..": [[space]]")
else
print("Char "..i..": "..char[i])
end
end
답변
문자열을 생성하기 위해 반복하고 load ()를 사용하여이 문자열을 테이블로 반환합니다.
itab=function(char)
local result
for i=1,#char do
if i==1 then
result=string.format('%s','{')
end
result=result..string.format('\'%s\'',char:sub(i,i))
if i~=#char then
result=result..string.format('%s',',')
end
if i==#char then
result=result..string.format('%s','}')
end
end
return load('return '..result)()
end
dump=function(dump)
for key,value in pairs(dump) do
io.write(string.format("%s=%s=%s\n",key,type(value),value))
end
end
res=itab('KOYAANISQATSI')
dump(res)
내 놓는다 …
1=string=K
2=string=O
3=string=Y
4=string=A
5=string=A
6=string=N
7=string=I
8=string=S
9=string=Q
10=string=A
11=string=T
12=string=S
13=string=I