最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++解析命令行參數(shù)的實現(xiàn)原理與代碼詳解

 更新時間:2025年10月12日 11:19:18   作者:liulilittle  
在C++程序開發(fā)中,命令行參數(shù)解析是一項基礎(chǔ)且關(guān)鍵的技術(shù),本文將從整體架構(gòu)到具體實現(xiàn),全面剖析這個命令行參數(shù)解析庫的每個組成部分,為每行代碼添加詳細注解,感興趣的小伙伴可以了解下

1. 引言:命令行參數(shù)解析的重要性

在C++程序開發(fā)中,命令行參數(shù)解析是一項基礎(chǔ)且關(guān)鍵的技術(shù),它使程序能夠在啟動時接收用戶輸入的配置信息,從而增加程序的靈活性和可配置性。無論是簡單的工具還是復(fù)雜的應(yīng)用程序,良好的命令行接口都能顯著提升用戶體驗和程序的專業(yè)性。本文將分析一個高效的C++命令行參數(shù)解析實現(xiàn),逐行解讀其代碼邏輯和設(shè)計思想。

命令行參數(shù)解析的基本原理是處理main函數(shù)接收的argc(參數(shù)數(shù)量)和argv(參數(shù)向量)參數(shù)。傳統(tǒng)的解析方法需要手動遍歷參數(shù)數(shù)組,而現(xiàn)代解析庫提供了更優(yōu)雅的解決方案。本文分析的代碼實現(xiàn)了一種支持兩種格式(--name=value--name value)的解析算法,具有輕量級、高效和易用的特點。

在接下來的章節(jié)中,我們將從整體架構(gòu)到具體實現(xiàn),全面剖析這個命令行參數(shù)解析庫的每個組成部分,為每行代碼添加詳細注解,并通過流程圖和示例展示其工作原理。

2. 代碼整體結(jié)構(gòu)與設(shè)計思路

2.1 總體架構(gòu)概述

該命令行參數(shù)解析實現(xiàn)采用模塊化設(shè)計,包含多個功能互補的函數(shù)。核心函數(shù)包括參數(shù)獲取、存在性檢查、幫助命令識別等,通過函數(shù)重載提供靈活的使用方式。整個設(shè)計遵循了單一職責(zé)原則,每個函數(shù)只負責(zé)一個明確的邏輯功能。

2.2 核心設(shè)計特點

  • 雙格式支持:同時支持--name=value--name value兩種參數(shù)格式
  • 類型安全:通過重載函數(shù)提供布爾值、字符串等不同類型的參數(shù)獲取
  • 默認值機制:所有參數(shù)獲取函數(shù)都支持默認值返回,增強魯棒性
  • 幫助命令檢測:內(nèi)置常見幫助命令識別,提升用戶體驗
  • 輕量級實現(xiàn):不依賴外部庫,代碼簡潔高效

這種設(shè)計使得該解析器既適合簡單快速開發(fā),也能滿足復(fù)雜命令行接口的需求。

3. 基礎(chǔ)函數(shù)實現(xiàn)剖析

3.1 GetCommandArgument(int argc, const char** argv) - 命令行字符串整合

此函數(shù)是解析器的基礎(chǔ),負責(zé)將命令行參數(shù)數(shù)組整合為單個字符串,便于后續(xù)處理。

ppp::string GetCommandArgument(int argc, const char** argv) noexcept {
    // 參數(shù)合法性檢查:確保argv非空且參數(shù)數(shù)量有效
    if (NULL == argv || argc <= 1) {
        return "";  // 參數(shù)不足時返回空字符串
    }
    
    ppp::string line;  // 用于存儲整合后的命令行字符串
    
    // 遍歷所有參數(shù)(從索引1開始,跳過程序名)
    for (int i = 1; i < argc; i++) {
        line.append(RTrim(LTrim<ppp::string>(argv[i])));  // 去除參數(shù)兩端空白字符后追加
        line.append(" ");  // 參數(shù)間添加空格分隔符
    }
    
    return line;  // 返回整合后的命令行字符串
}

代碼邏輯分析

  • 參數(shù)驗證:首先檢查argv指針是否有效以及參數(shù)數(shù)量是否大于1(因為argv[0]通常是程序名)
  • 字符串構(gòu)建:使用循環(huán)從索引1開始遍歷所有參數(shù),跳過程序名稱本身
  • 空白處理:對每個參數(shù)使用LTrimRTrim去除首尾空白,確保格式統(tǒng)一
  • 空格分隔:在每個參數(shù)后添加空格,模擬原始命令行格式

關(guān)鍵技術(shù)點

  • noexcept關(guān)鍵字確保函數(shù)不會拋出異常,增強穩(wěn)定性
  • 使用ppp::string自定義字符串類,提供更好的內(nèi)存管理
  • 修剪函數(shù)防止多余空白干擾后續(xù)解析邏輯

這個函數(shù)的效果是將命令行參數(shù)如./program --name=value --verbose轉(zhuǎn)換為統(tǒng)一的字符串格式"--name=value --verbose ",為后續(xù)解析做準備。

3.2 HasCommandArgument函數(shù) - 參數(shù)存在性檢測

此函數(shù)負責(zé)檢測指定的命令行參數(shù)是否存在,是解析器的基礎(chǔ)查詢功能。

bool HasCommandArgument(const char* name, int argc, const char** argv) noexcept {
    // 第一步:參數(shù)有效性驗證
    if (NULL == name || *name == '\x0') {  // 檢查名稱是否為空指針或空字符串
        return false;  // 無效參數(shù)名直接返回false
    }
    
    // 第二步:獲取完整命令行文本
    ppp::string commandText = ppp::GetCommandArgument(argc, argv);
    if (commandText.empty()) {  // 檢查命令行是否為空
        return false;  // 無參數(shù)時直接返回false
    }
    
    // 第三步:定義內(nèi)部查找lambda函數(shù)
    auto fx = ppp::string& commandText, const ppp::string& name noexcept -> bool {
        // 在命令行文本中查找參數(shù)名
        std::size_t index = commandText.find(name);
        if (index == ppp::string::npos) {  // 未找到目標字符串
            return false;
        }
        
        // 檢查參數(shù)名位置是否合法(行首或前面有空格)
        if (index == 0) {  // 參數(shù)位于行首
            return true;
        }
        
        char ch = commandText[index - 1];  // 獲取參數(shù)名前一個字符
        if (ch == ' ') {  // 前一個字符是空格,表明是獨立參數(shù)
            return true;
        } else {
            return false;  // 前一個字符不是空格,可能是其他參數(shù)的一部分
        }
    };
    
    // 第四步:使用兩種格式檢查參數(shù)存在性
    bool result = false;  // 初始化結(jié)果為false
    ppp::string keyWithEqual = name + ppp::string("=");  // 構(gòu)造"name="格式的鍵
    ppp::string keyWithSpace = name + ppp::string(" ");  // 構(gòu)造"name "格式的鍵
    
    // 檢查兩種可能的參數(shù)格式
    result = result || fx(commandText, keyWithEqual);  // 檢查"--name="格式
    result = result || fx(commandText, keyWithSpace);  // 檢查"--name "格式
    
    return result;  // 返回最終檢測結(jié)果
}

算法流程圖

關(guān)鍵技術(shù)點

  • 雙格式支持:同時檢測--name=value--name value兩種參數(shù)格式
  • 邊界檢查:通過檢查參數(shù)名前字符確保匹配的是完整參數(shù)名而非子字符串
  • Lambda函數(shù):使用內(nèi)部lambda函數(shù)避免代碼重復(fù),提高可讀性
  • 短路求值:使用||運算符進行短路求值,提高檢測效率

此函數(shù)能夠準確區(qū)分--name--name2等相似參數(shù),避免誤匹配,確保檢測的準確性。

4. 核心解析算法解析

4.1 GetCommandArgument(const char* name, …) - 參數(shù)值提取核心函數(shù)

這是解析器最核心的函數(shù),負責(zé)從命令行中提取特定參數(shù)對應(yīng)的值。

ppp::string GetCommandArgument(const char* name, int argc, const char** argv) noexcept {
    // 第一階段:參數(shù)驗證和初始化
    if (NULL == name || argc <= 1) {  // 檢查名稱指針和參數(shù)數(shù)量
        return "";  // 基本驗證失敗返回空字符串
    }
    
    ppp::string key1 = name;  // 創(chuàng)建參數(shù)名副本
    if (key1.empty()) {  // 檢查參數(shù)名是否為空
        return "";  // 空參數(shù)名返回空字符串
    }
    
    // 構(gòu)造兩種查找鍵格式
    ppp::string key2 = key1 + " ";  // "name "格式,用于空格分隔的參數(shù)
    key1.append("=");  // "name="格式,用于等號連接的值
    
    // 獲取完整命令行文本
    ppp::string line = GetCommandArgument(argc, argv);
    if (line.empty()) {  // 檢查命令行是否為空
        return "";  // 空命令行返回空字符串
    }
    
    // 第二階段:查找參數(shù)位置
    ppp::string* key = addressof(key1);  // 首先嘗試"name="格式
    std::size_t L = line.find(*key);  // 查找鍵出現(xiàn)位置
    
    if (L == ppp::string::npos) {  // 第一種格式未找到
        key = addressof(key2);  // 切換到"name "格式
        L = line.find(*key);  // 重新查找
        if (L == ppp::string::npos) {  // 第二種格式也未找到
            return "";  // 參數(shù)不存在返回空字符串
        }
    }
    
    // 第三階段:驗證參數(shù)名完整性
    if (L) {  // 參數(shù)名不是行首位置(L > 0)
        char ch = line[L - 1];  // 檢查參數(shù)名前字符
        if (ch != ' ') {  // 前一個字符不是空格
            return "";  // 說明不是獨立參數(shù)名,返回空
        }
    }
    
    // 第四階段:提取參數(shù)值
    ppp::string cmd;  // 存儲提取的結(jié)果值
    std::size_t M = L + key->size();  // 計算值開始位置(鍵結(jié)束位置)
    std::size_t R = line.find(' ', L);  // 查找下一個空格位置
    
    if (M >= R) {  // 處理無空格的情況(參數(shù)值可能為空或到行尾)
        R = ppp::string::npos;  // 標記為未找到空格
        
        // 手動查找值結(jié)束位置
        for (std::size_t I = M, SZ = line.size(); I < SZ; I++) {
            int ch = line[I];  // 遍歷每個字符
            if (ch == ' ') {  // 找到空格
                R = I;  // 記錄結(jié)束位置
                L = M;  // 調(diào)整開始位置
                break;  // 退出循環(huán)
            }
        }
        
        if (!L || L == ppp::string::npos) {  // 位置驗證失敗
            return "";  // 返回空字符串
        }
    }
    
    // 第五階段:根據(jù)找到的位置提取子字符串
    if (R == ppp::string::npos) {  // 沒有找到后續(xù)空格(值到行尾)
        if (M != line.size()) {  // 確保值開始位置有效
            cmd = line.substr(M);  // 提取從M到末尾的子字符串
        }
    } else {  // 找到了值結(jié)束位置
        int S = (int)(R - M);  // 計算值長度
        if (S > 0) {  // 長度有效
            cmd = line.substr(M, S);  // 提取指定長度的子字符串
        }
    }
    
    return cmd;  // 返回提取的參數(shù)值
}

解析過程可視化

4.2 算法核心邏輯詳解

該函數(shù)實現(xiàn)了雙模式解析算法,能夠智能識別和處理兩種常見的命令行參數(shù)格式:

等號連接格式 (--name=value):

  • 直接查找"name="模式
  • 值從等號后開始直到下一個空格或行尾
  • 示例:--port=8080 → 值"8080"

空格分隔格式 (--name value):

  • 查找"name "模式(注意包含空格)
  • 值從空格后開始直到下一個空格或行尾
  • 示例:--port 8080 → 值"8080"

邊界情況處理

  • 參數(shù)名驗證:通過檢查前導(dǎo)字符確保匹配完整參數(shù)名
  • 值提取精度:準確計算值的起始和結(jié)束位置
  • 空值處理:正確處理--name=--name 后無值的情況

這種設(shè)計使解析器能夠靈活適應(yīng)不同的命令行習(xí)慣,提供良好的用戶體驗。

5. 實用功能函數(shù)分析

5.1 重載函數(shù)集 - 類型安全的值獲取

為了提高代碼的實用性和類型安全性,解析器提供了一系列重載函數(shù),支持不同類型的參數(shù)獲取和默認值機制。

// 布爾值獲取函數(shù):將參數(shù)值轉(zhuǎn)換為布爾類型
bool GetCommandArgument(const char* name, int argc, const char** argv, bool defaultValue) noexcept {
    // 獲取字符串形式的參數(shù)值
    ppp::string str = GetCommandArgument(name, argc, argv);
    if (str.empty()) {  // 值為空時返回默認值
        return defaultValue;
    }
    
    // 將字符串轉(zhuǎn)換為布爾值
    return ToBoolean(str.data());  // 調(diào)用轉(zhuǎn)換函數(shù)
}

// 字符串獲取函數(shù)(C字符串默認值版本)
ppp::string GetCommandArgument(const char* name, int argc, const char** argv, const char* defaultValue) noexcept {
    ppp::string defValue;  // 創(chuàng)建默認值字符串
    if (defaultValue) {  // 檢查默認值指針是否有效
        defValue = defaultValue;  // 賦值默認值
    }
    
    // 調(diào)用主獲取函數(shù),傳入默認值
    return GetCommandArgument(name, argc, argv, defValue);
}

// 字符串獲取函數(shù)(字符串對象默認值版本)
ppp::string GetCommandArgument(const char* name, int argc, const char** argv, const ppp::string& defaultValue) noexcept {
    // 獲取參數(shù)值
    ppp::string str = GetCommandArgument(name, argc, argv);
    // 三目運算符:值為空時返回默認值,否則返回實際值
    return str.empty() ? defaultValue : str;
}

設(shè)計模式分析

  • 函數(shù)重載:通過重載提供統(tǒng)一接口支持不同類型
  • 默認值機制:所有函數(shù)都支持默認值,避免空值導(dǎo)致的異常
  • 類型轉(zhuǎn)換:提供字符串到布爾值的自動轉(zhuǎn)換,增強實用性

這些重載函數(shù)使解析器API更加友好,開發(fā)者可以根據(jù)需要選擇合適的數(shù)據(jù)類型。

5.2 IsInputHelpCommand函數(shù) - 幫助命令智能檢測

此函數(shù)專門用于檢測常見的幫助命令,是命令行工具的基礎(chǔ)功能之一。

bool IsInputHelpCommand(int argc, const char* argv[]) noexcept {
    // 定義支持的幫助命令列表
    const int HELP_COMMAND_COUNT = 4;  // 幫助命令數(shù)量
    const char* HELP_COMMAND_LIST[HELP_COMMAND_COUNT] = {
        "-h",      // 短格式簡寫
        "--h",     // 長格式簡寫  
        "-help",   // 短格式完整
        "--help"   // 長格式完整
    };
    
    // 遍歷所有幫助命令進行檢測
    for (int i = 0; i < HELP_COMMAND_COUNT; i++) {
        const char* command = HELP_COMMAND_LIST[i];  // 獲取當(dāng)前檢測的命令
        if (HasCommandArgument(command, argc, argv)) {  // 檢查命令是否存在
            return true;  // 找到任一幫助命令即返回true
        }
    }
    
    return false;  // 未找到任何幫助命令返回false
}

幫助命令檢測策略

  • 多格式支持:覆蓋常見的幫助命令變體
  • 短路檢測:找到第一個匹配命令立即返回,提高效率
  • 統(tǒng)一接口:基于現(xiàn)有的HasCommandArgument函數(shù),確保檢測邏輯一致

這個功能使程序能夠自動識別用戶請求幫助的意圖,是實現(xiàn)友好命令行工具的重要組成部分。

6. 算法性能分析

6.1 時間復(fù)雜度分析

命令行參數(shù)解析算法的時間復(fù)雜度主要取決于字符串查找和匹配操作。以下是關(guān)鍵操作的時間復(fù)雜度分析:

函數(shù)主要操作時間復(fù)雜度最壞情況優(yōu)化策略
GetCommandArgument字符串查找、子串提取O(n)O(n×m)減少不必要的字符串拷貝
HasCommandArgument字符串查找、模式匹配O(n)O(n×m)使用高效查找算法
參數(shù)值提取子串提取、邊界檢查O(k)O(n)預(yù)計算字符串長度

其中n是命令行字符串長度,m是參數(shù)名長度,k是參數(shù)值長度。

6.2 內(nèi)存使用優(yōu)化

解析器在內(nèi)存使用方面采用了多項優(yōu)化策略:

  • 字符串視圖應(yīng)用:避免不必要的字符串拷貝,使用引用或視圖
  • 棧分配優(yōu)先:局部變量盡量使用棧內(nèi)存,減少堆分配
  • 延遲構(gòu)造:僅在需要時創(chuàng)建字符串對象
  • 內(nèi)存復(fù)用:重復(fù)使用已分配的內(nèi)存緩沖區(qū)

7. 實際應(yīng)用與實踐

7.1 完整使用示例

下面展示如何在真實項目中使用該命令行參數(shù)解析器:

#include <iostream>
#include "command_parser.h"  // 包含解析器頭文件

int main(int argc, const char** argv) {
    // 檢查幫助命令
    if (ppp::IsInputHelpCommand(argc, argv)) {
        std::cout << "用法: " << argv[0] << " [選項]" << std::endl;
        std::cout << "選項:" << std::endl;
        std::cout << "  --host=<地址>    服務(wù)器地址(必需)" << std::endl;
        std::cout << "  --port=<端口>    服務(wù)器端口(默認:8080)" << std::endl;
        std::cout << "  --verbose        啟用詳細輸出" << std::endl;
        return 0;
    }
    
    // 獲取必需參數(shù)
    std::string host = ppp::GetCommandArgument("--host", argc, argv, "");
    if (host.empty()) {
        std::cerr << "錯誤: 必須指定 --host 參數(shù)" << std::endl;
        return 1;
    }
    
    // 獲取可選參數(shù)(帶默認值)
    int port = ppp::GetCommandArgument("--port", argc, argv, 8080);
    bool verbose = ppp::GetCommandArgument("--verbose", argc, argv, false);
    
    // 應(yīng)用參數(shù)
    std::cout << "連接到 " << host << ":" << port << std::endl;
    if (verbose) {
        std::cout << "詳細模式已啟用" << std::endl;
    }
    
    // 程序主邏輯...
    return 0;
}

7.2 實踐建議

基于該解析器的特性,推薦以下最佳實踐:

參數(shù)命名規(guī)范

  • 使用統(tǒng)一前綴(如--)區(qū)分參數(shù)類型
  • 參數(shù)名應(yīng)具有描述性和唯一性
  • 同時提供長短格式支持重要參數(shù)

錯誤處理策略

  • 對必需參數(shù)進行顯式驗證
  • 提供清晰的錯誤信息和用法提示
  • 使用默認值降低用戶輸入負擔(dān)

性能優(yōu)化建議

  • 避免在循環(huán)中重復(fù)解析相同參數(shù)
  • 對頻繁使用的參數(shù)進行緩存
  • 按需進行參數(shù)驗證和轉(zhuǎn)換

這些實踐能夠幫助開發(fā)者構(gòu)建更加健壯和用戶友好的命令行應(yīng)用程序。

8. 總結(jié)

本文詳細剖析了一個高效的C++命令行參數(shù)解析算法的實現(xiàn)原理和代碼細節(jié)。該解析器通過巧妙的字符串處理和模式匹配算法,實現(xiàn)了對常見命令行參數(shù)格式的靈活支持。

技術(shù)回顧

  • 雙格式解析:同時支持--name=value--name value格式
  • 類型安全:通過重載函數(shù)提供多種數(shù)據(jù)類型支持
  • 魯棒性強:完善的錯誤處理和默認值機制
  • 性能優(yōu)異:線性時間復(fù)雜度和優(yōu)化的內(nèi)存使用
  • 易于集成:頭文件Only,無需外部依賴

這個命令行參數(shù)解析器體現(xiàn)了C++編程的許多最佳實踐,包括資源管理、算法優(yōu)化和API設(shè)計等,是學(xué)習(xí)現(xiàn)代C++編程的優(yōu)秀范例。

到此這篇關(guān)于C++解析命令行參數(shù)的實現(xiàn)原理與代碼詳解的文章就介紹到這了,更多相關(guān)C++解析命令行參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C/C++ 內(nèi)存管理詳解:從內(nèi)存分布到 new/delete 原理解析

    C/C++ 內(nèi)存管理詳解:從內(nèi)存分布到 new/delete 原理解析

    本文給大家介紹C/C++ 內(nèi)存管理詳解:從內(nèi)存分布到 new/delete 原理解析,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2026-05-05
  • C語言深入細致講解動態(tài)內(nèi)存管理

    C語言深入細致講解動態(tài)內(nèi)存管理

    動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動態(tài)內(nèi)存的管理
    2022-05-05
  • C/C++線程退出的四種方法小結(jié)

    C/C++線程退出的四種方法小結(jié)

    本文主要介紹了C/C++線程退出的四種方法小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C++詳細講解引用類型

    C++詳細講解引用類型

    引用指的是對一個對象的引用。那么什么是對象?在c++中狹義的對象指的是用類,結(jié)構(gòu),聯(lián)合等復(fù)雜數(shù)據(jù)類型來聲明的變量,如?MyClass?myclass,CDialog?mydlg,等等
    2022-07-07
  • wince禁止程序標題欄上的退出按鈕示例

    wince禁止程序標題欄上的退出按鈕示例

    這篇文章主要介紹了wince禁止程序標題欄上的退出按鈕示例,需要的朋友可以參考下
    2014-02-02
  • Qt?QGraphicsItem?移動時出現(xiàn)殘影問題記錄

    Qt?QGraphicsItem?移動時出現(xiàn)殘影問題記錄

    自定義QGraphicsItem時,繪制rect,對象移動時出現(xiàn)殘影的問題記錄,本文給大家介紹Qt?QGraphicsItem?移動時出現(xiàn)殘影問題記錄,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • C++創(chuàng)建窗口程序的實現(xiàn)示例

    C++創(chuàng)建窗口程序的實現(xiàn)示例

    Windows窗體應(yīng)用程序是C#語言中的一個重要應(yīng)用,本文主要介紹了C++創(chuàng)建窗口程序的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • c++ 中vector 常見用法

    c++ 中vector 常見用法

    這篇文章主要給大家分享的是c++ 中vector 常見用法,,vector有兩個參數(shù),一個是size,表示當(dāng)前vector容器內(nèi)存儲的元素個數(shù),一個是capacity,表示當(dāng)前vector在內(nèi)存中申請的這片區(qū)域所能容納的元素個數(shù),下面來看看文章的詳細內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • C++函數(shù)指針詳解

    C++函數(shù)指針詳解

    這篇文章主要介紹了C++函數(shù)指針詳解,通過文字描述C++函數(shù)指針基礎(chǔ)概念,內(nèi)涵詳細的代碼實現(xiàn)和解析,希望對你能夠有所幫助
    2021-06-06
  • Visual Studio Code安裝和配置的教程

    Visual Studio Code安裝和配置的教程

    這篇文章主要介紹了Visual Studio Code安裝和配置,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03

最新評論

繁峙县| 新乐市| 冕宁县| 安乡县| 嘉义县| 长春市| 宁波市| 晋宁县| 泰来县| 崇明县| 蒙城县| 万山特区| 扎赉特旗| 达拉特旗| 西青区| 长岭县| 保康县| 佛学| 卓资县| 昌江| 罗城| 泽州县| 墨玉县| 新昌县| 寻乌县| 青浦区| 沁水县| 高州市| 湘潭县| 临安市| 岗巴县| 威信县| 钟山县| 建平县| 措美县| 秭归县| 临西县| 渑池县| 黑山县| 原阳县| 库尔勒市|