كيفية تكرار الأحرف الفردية في لوا السلسلة ؟

StackOverflow https://stackoverflow.com/questions/829063

  •  06-07-2019
  •  | 
  •  

سؤال

لدي سلسلة في لوا وتريد تكرار الأحرف الفردية في ذلك.ولكن لا يوجد قانون حاولت يعمل الرسمي دليل يظهر فقط كيفية البحث و استبدال سلاسل فرعية :(

str = "abcd"
for char in str do -- error
  print( char )
end

for i = 1, str:len() do
  print( str[ i ] ) -- nil
end
هل كانت مفيدة؟

المحلول

في لوا 5.1، يمكنك تكرار الشخصيات من سلسلة هذا في عدة طرق.

وحلقة أساسية ستكون كما يلي:

for i = 1, #str do
    local c = str:sub(i,i)
    -- do something with c
end

ولكن قد تكون أكثر كفاءة في استخدام النمط مع string.gmatch() للحصول على مكرر على الشخصيات:

for c in str:gmatch"." do
    -- do something with c
end

وأو حتى استخدام string.gsub() استدعاء دالة لكل شار:

str:gsub(".", function(c)
    -- do something with c
end)

في كل ما سبق، لقد اتخذت الاستفادة من حقيقة أن يتم تعيين وحدة string باعتباره metatable لجميع قيم السلسلة، لذلك يمكن أن يسمى مهامها كأعضاء باستخدام تدوين :. لقد استعملت أيضا (جديد إلى 5.1، IIRC) # للحصول على طول السلسلة.

وأفضل إجابة لطلبك تعتمد على الكثير من العوامل، والمقاييس وصديقك إذا كان الأداء هو الذهاب الى يهم.

وقد ترغب في تقييم <م> لماذا عليك أعاد فوق الحروف، والنظر في واحدة من وحدات التعبير العادية التي تم بد أن لوا، أو لنهج نظرة الحديثة إلى روبرتو < وأ href = "http://www.inf.puc-rio.br/~roberto/lpeg.html" يختلط = "noreferrer"> lpeg الوحدة الذي ينفذ في التحليل Grammers التعبير عن لوا.

نصائح أخرى

إذا كنت تستخدم لوا 5، في محاولة:

for i = 1, string.len(str) do
    print( string.sub(str, i, i) )
end

واعتمادا على المهمة التي بين أيدينا قد يكون أسهل للاستخدام string.byte . بل هو أيضا أسرع الطرق لأنها تتجنب خلق فرعية جديدة happends أن تكون مكلفة جدا في لوا بفضل تجزئة كل سلسلة جديدة وفحص إذا ما هو معروف بالفعل. يمكنك قبل حساب مدونة حرف تبحث مع نفسه 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

هناك بالفعل الكثير من الطرق الجيدة في توفير إجابات (هنا, هنا و هنا).إذا كانت السرعة هي ما أنت في المقام الأول تبحث عن, يجب عليك أن تنظر بالتأكيد القيام بهذه المهمة من خلال لوا ل C API ، والتي هي عدة مرات أسرع من الخام لوا رمز.عند العمل مع مسبقة قطع (على سبيل المثال. وظيفة تحميل), الفرق ليس كبيرا, ولكن لا تزال كبيرة.

أما بالنسبة نقية لوا الحلول ، اسمحوا لي أن حصة الصغير هذا المعيار ، لقد صنعت.وهو يغطي كل تقدم الجواب على هذا التاريخ ويضيف بعض التحسينات.لا يزال, الشيء الأساسي هو أن تنظر:

كم مرة سوف تحتاج إلى تكرار أكثر من الأحرف في السلسلة ؟

  • إذا كان الجواب "مرة واحدة" ، من يجب أن ننظر أولا جزء من banchmark ("الخام السرعة").
  • وإلا الجزء الثاني سوف توفر أكثر دقة تقدير ، لأنه يوزع السلسلة إلى الطاولة ، وهو أسرع بكثير تكرار أكثر.يجب عليك أن تنظر أيضا كتابة وظيفة بسيطة عن هذا @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))

مثال الإخراج (لوا 5.3.4, ويندوز):

-----------------------
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 الإصدار الأسرع حتى عند تحويل charcodes إلى حرف (التي ليس من الضروري دائما و يعتمد على الاستخدام).

كما كنت قد لاحظت على الأرجح ، لقد جعلت بعض الافتراضات بناء على المعايير السابقة وتطبيقها على كود:

  1. وظائف المكتبة يجب أن يكون دائما مترجمة في حالة استخدامها داخل الحلقات ، لأنه هو الكثير أسرع.
  2. إدخال عنصر جديد في لوا الجدول هو أسرع بكثير باستخدام tbl[idx] = value من table.insert(tbl, value).
  3. حلقات من خلال الجدول باستخدام for i = 1, #tbl هو أسرع قليلا من for k, v in pairs(tbl).
  4. دائما تفضل النسخة مع أقل وظيفة المكالمات, لأن الدعوة نفسها يضيف قليلا إلى وقت التنفيذ.

آمل أن يساعد.

وجميع الناس تشير إلى طريقة أقل الأمثل

وسيكون أفضل:

    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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top