2008-09-05 25 views
1

我想知道是否有一個開放源碼庫或算法,可以擴大非數字範圍。舉例來說,如果你有1A9A你應該得到圖書館或算法,以爆炸字母數字範圍

1A, 2A, 3A, 4A, 5A, 6A, 7A, 8A, 9A. 

我試過谷歌搜索這一點,最好的我能想出是正則表達式,將擴大與破折號NUMERICS(1-3變成1,2 ,3)。

回答

0

我試圖離開它有點打開,因爲可能性的數量是驚人的。我相信在沒有經過大量技術細節的情況下,這些無法100%回答的問題之一被認爲是「好」或「壞」範圍。我只是想找到一個關於其他人如何解決這個問題的想法的跳躍點。我希望有人寫了一篇博客文章,解釋他們如何解決這個問題,或者創建一個完整的庫來處理這個問題。

0

我想說的解決方案的第一步將是如何定義字符和數字互動,形成一個序列。給出的例子並不清楚,因爲您至少會假定它運行1A,1B ... 8Y,8Z,9A--假設您的輸入被限制爲小數,然後是單個字符。

如果你可以定義字符和小數的連續序列,那麼你將僅僅​​是一些遞歸的問題/循環生成序列的一部分。例如,您可以假定輸入中的每個字符都是(1-9A-Z)中的一個,因此通過獲取字母字符的小數ascii值並減去55,可以很容易地實現連續性給你的範圍(1-35)

0

如果我們假設開始和結束範圍將遵循相同的交替模式,並限制數字的範圍0-9A-Z,我們可以認爲各組數字作爲的分量在多維座標中。例如,1A將對應於二維座標(1,A)(這是Excel用來標記其二維網格的行和列);而AA1BB2將是四維座標(AA,1,BB,2)

由於每個組件是獨立的,擴展兩個座標之間我們只是返回每個組件的膨脹的所有組合的範圍內。下面是我今天下午製作的一個快速實施。它適用於正常和字母數字的交替任意數量和處理大量字母的範圍(即從ABCDE,不只是ABCD)。

注意:這是一個實際實現的粗略草案(我明天起飛,所以它比平常更不精緻;)。所有關於錯誤處理,健壯性,(可讀性)等常見的注意事項都適用。

IEnumerable<string> ExpandRange(string start, string end) { 
    // Split coordinates into component parts. 
    string[] startParts = GetRangeParts(start); 
    string[] endParts = GetRangeParts(end); 

    // Expand range between parts 
    // (i.e. 1->3 becomes 1,2,3; A->C becomes A,B,C). 
    int length = startParts.Length; 
    int[] lengths = new int[length]; 
    string[][] expandedParts = new string[length][]; 
    for(int i = 0; i < length; ++i) { 
    expandedParts[i] = ExpandRangeParts(startParts[i], endParts[i]); 
    lengths[i] = expandedParts[i].Length; 
    } 

    // Return all combinations of expanded parts. 
    int[] indexes = new int[length]; 
    do { 
     var sb = new StringBuilder(); 
     for(int i = 0; i < length; ++i) { 
     int partIndex = indexes[i]; 
     sb.Append(expandedParts[i][partIndex]); 
     } 
     yield return sb.ToString(); 
    } while(IncrementIndexes(indexes, lengths)); 
} 

readonly Regex RangeRegex = new Regex("([0-9]*)([A-Z]*)"); 
string[] GetRangeParts(string range) { 
    // Match all alternating digit-letter components of coordinate. 
    var matches = RangeRegex.Matches(range); 
    var parts = 
    from match in matches.Cast<Match>() 
    from matchGroup in match.Groups.Cast<Group>().Skip(1) 
    let value = matchGroup.Value 
    where value.Length > 0 
    select value; 
    return parts.ToArray(); 
} 

string[] ExpandRangeParts(string startPart, string endPart) { 
    int start, end; 
    Func<int, string> toString; 

    bool isNumeric = char.IsDigit(startPart, 0); 
    if(isNumeric) { 
    // Parse regular integers directly. 
    start = int.Parse(startPart); 
    end = int.Parse(endPart); 
    toString = (i) => i.ToString(); 
    } 
    else { 
    // Convert alphabetic numbers to integers for expansion, 
    // then convert back for display. 
    start = AlphaNumberToInt(startPart); 
    end = AlphaNumberToInt(endPart); 
    toString = IntToAlphaNumber; 
    } 

    int count = end - start + 1; 
    return Enumerable.Range(start, count) 
    .Select(toString) 
    .Where(s => s.Length > 0) 
    .ToArray(); 
} 

bool IncrementIndexes(int[] indexes, int[] lengths) { 
    // Increment indexes from right to left (i.e. Arabic numeral order). 
    bool carry = true; 
    for(int i = lengths.Length; carry && i > 0; --i) { 
    int index = i - 1; 
    int incrementedValue = (indexes[index] + 1) % lengths[index]; 
    indexes[index] = incrementedValue; 
    carry = (incrementedValue == 0); 
    } 
    return !carry; 
} 

// Alphabetic numbers are 1-based (i.e. A = 1, AA = 11, etc, mod base-26). 
const char AlphaDigitZero = (char)('A' - 1); 
const int AlphaNumberBase = 'Z' - AlphaDigitZero + 1; 
int AlphaNumberToInt(string number) { 
    int sum = 0; 
    int place = 1; 
    foreach(char c in number.Cast<char>().Reverse()) { 
    int digit = c - AlphaDigitZero; 
    sum += digit * place; 
    place *= AlphaNumberBase; 
    } 
    return sum; 
} 

string IntToAlphaNumber(int number) { 
    List<char> digits = new List<char>(); 
    while(number > 0) { 
    int digit = number % AlphaNumberBase; 
    if(digit == 0) // Compensate for 1-based alphabetic numbers. 
     return ""; 

    char c = (char)(AlphaDigitZero + digit); 
    digits.Add(c); 
    number /= AlphaNumberBase; 
    } 

    digits.Reverse(); 
    return new string(digits.ToArray()); 
} 
1

正如其他人所指出的那樣,更具體一些將是有用的。我不認爲你可以期望有一個庫可以根據你想要的字符串的任意順序生成範圍。

如果你可以簡單地定義任何給定的字符串的繼任者是什麼,那麼解決方案是很容易的。也就是說,如果你在字符串上有一個後繼函數S(例如與S('3A') = '4A'),那麼像下面可以使用:我已在過去使用

s = initial_string 
while s != final_string do 
    output s 
    s = S(s) 
output s 

東西產生給定長度l的並與給定範圍b的字符e所有字符串,是下面一塊(僞)代碼。它可以很容易地適應各種各樣的變化。

// initialise s with b at every position 
for i in [0..l) do 
    s[i] = b 
done = false 
while not done do 
    output s 
    j = 0 
    // if s[j] is e, reset it to b and "add carry" 
    while j < l and s[j] == e do 
    s[j] = b 
    j = j + 1 
    if j == l then 
     done = true 
    if not done then 
    s[j] = s[j] + 1 

例如,在你只需要改變的初始化一個特定的字符串開始。要設置結束,您只需要更改內部行爲,同時單獨處理位置l(限制爲該位置結束字符串中的字符,如果達到遞減l)。

+0

只是想提一提,如果您認爲問題是線性的(即將`A1B2`視爲單個數字),這是一個很好的解決方案。我仍然認爲這個問題是多維的,但我想我們只能等待作者澄清:) – 2008-09-06 14:30:40