سؤال

أنا أحاول أن منشئ فئة الرسم البياني يقبل سلسلة بمثابة المعلمة و يستخدم هذا بناء على الرسم البياني.

سلسلة تنسيق على النحو التالي: |vertex list|Edges list| على سبيل المثال |1,2,3,4,15|(1->2),(3->2),(4->15)|

الفكرة هي أن منشئ سوف تأخذ القيم من السلسلة ثم تعرف على تنفيذ الإجراءات التالية (إدراج الذروات إلى قمة قائمة ثم إدراج حواف في حواف قائمة):

addVertex(1)  
addVertex(2)  
addVertex(3)  
addVertex(4)  
addVertex(15)  
addEdge(1,2)  
addEdge(3,2)  
addEdge(4,15)  

كنت قد أدلى به للتو بضعة "من أجل" حلقات مسح السلسلة, ولكن أنا لا أعرف ماذا تفعل حيال ضعف(أو أكثر) أرقام.بدأت تخيل كل أنواع على محمل الجد معقدة عن الحلقات و أنا أتساءل عما اذا كان أي شخص هنا يمكن أن حصة معي أي أكثر ذكاء طرق استخراج واستخدام هذه البيانات.

هل كانت مفيدة؟

المحلول

ويمكنك استخدام stringstream واستخدام المشغل استخراج تيار للحصول على الأعداد الصحيحة الخاصة بك.

string s("12 34");
istringstream ss(s);
int x, y;
ss >> x >> y;

وبما أن هذا هو الواجب المنزلي، وأحثكم على استكشاف الاحتمالات ومعرفة كاملة رمز لنفسك.

نصائح أخرى

يبدو أن الحصول على طغت تبحث في كل شيء.كسرها إلى قطع...المهام.ما كنت تحاول القيام به يبدو أن تكون منفصلة وظائف هنا.

  1. Tokenizing
  2. تحليل القمم
  3. تحليل حواف
  4. التنفيذ على القمم
  5. التنفيذ على حواف

5 وظائف أكثر أو أقل.

كنت ترغب في tokenize على أساس الأنابيب (|) حتى تأخذ فرعية على أساس أنبوب تمرير كل جانب المناسب محلل تحليل على الفواصل وهلم جرا.

لن تفعل ذلك بالنسبة لك, ولكن أتمنى أن تحصل على التفكير في الاتجاه الصحيح.تعلم برنامج ليس كثيرا عن أي لغة معينة ، ولكن عن تغيير طريقة تفكيرك.

وأنا لم تستخدم من قبل، ولكن هناك دفعة <لأ href = "http://www.boost.org/doc/libs/1_38_0/libs/tokenizer/tokenizer.htm" يختلط = "نوفولو noreferrer" > الدرجة tokenizer . هل يمكن أن يكون ذلك بسهولة كسر شيء إلى مكونات لك دون كل-حلقات ل.

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

void skipWhiteSpace(const char*& first , const char* last) {
    // do whatever need to be done to skip white space
}

// parse integer only, no error checking is performed
bool parseVertex(const char*& first , const char* last) {
    skipWhiteSpace(first, last);
    const char* numBegin = first;
    for (; first != last && ::isdigit(static_cast<unsigned char>(*first)); 
        ++first) {}
    if (numBegin != first) {
        std::cout << "addVertex(" << std::string(numBegin, first) << ")" << std::endl;
        return true;
    }

    return false;
}

bool parseComma(const char*& first , const char* last) {
    skipWhiteSpace(first, last);
    if (first != last && ',' == *first) {
        ++first;
        return true;
    }

    return false;
}

// VL := V (, VL)
// a vertex list (VL) is a vertex (V) followed by a comma than another vertex list
bool parseVertexList(const char*& first, const char* last) {
    if (parseVertex(first, last)) {
        parseComma(first, last) && parseVertexList(first, last);
        return true;
    }

    return false;
}
}

void test() {
    const char* str = "1,2,3,4,15";
    parseVertexList(str, str + sizeof("1,2,3,4,15"));
}

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

إذا نقرر في المثال "| 1،2،3،4،15 | (1-> 2)، (3-> 2)، (4-> 15) |" أن السلسلة بأكملها هي "مضلع"، كنا إرسال parsePolygon ()، التي من شأنها أن ننظر بشيء من هذا القبيل:

void parsePolygon (Buffer& b)
{
  parseVertices (b);
  parseEdges (b);
}

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

وparseVertices قد تبدو هذه:

void parseVertices (Buffer& b)
{
  if (b.peek() != '|') { /* error */ }
  b.consume (); // burn the '|'
  parseVertexList (b);
  if (b.peek() != '|') { /* error */ }
  b.consume (); // burn the '|'
}

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

وهناك مثالان المزيد ... parseVertexList وparseNumber قد تبدو مثل هذا:

void parseVertexList (Buffer& b)
{
  addVertex (parseNumber (b));
  while (b.peek() == ',')
  {
     b.consume (); // eat the comma
     addVertex (parseNumber (b));
  }
}

int parseNumber (Buffer& b)
{
  char accum[80] = { '0' };  // sensible default in case of failure
  int accumPos = 0;
  while (isDigit (b.peek())
  {
    accum[accumPos++] = b.consume();
  }
  return atoi(accum);
}

وهذا هو كل شيء سريع جدا وقذرة، ولكن نأمل أن تعطيك فكرة كيفية عمل هذه التقنية. يمكنك امتزاج التعامل مع الاعراب كما هو موضح أعلاه، حيث وظيفة parseVertexList في الواقع لا في addVertex يدعو لك.

وأعتقد أن هذا هو حقا واحدة من أبسط الطرق للإعراب اليدوي. ومن الناحية المثالية سنكون دائما قادرا على استخدام موزعي ولدت مثل روح دفعة أو pyparsing أو يكس / ياك، ولكن الحياة ليست دائما على ما يرام، وخاصة بالنسبة الواجبات المنزلية.

وأيضا أعتقد أنه من الجدير بالذكر أن التقنية المذكورة أعلاه يمكن أن يكون هناك الكثير من مبالغة بعض المواقف التوزيع.

واستخدام stringstream . لاحظ المثال على تلك الصفحة للقراءة في أرقام مع istringstream.

وأنا بالتأكيد استخدام هذه المشكلة ذريعة للعب مع دفعة روح ! يجب كتابة قليلا النحوي لهذه اللغة صغيرة يكون هناك الكثير من المرح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top