ฉันจะตรวจสอบว่าสตริง C ++ std :: เริ่มต้นด้วยสตริงที่แน่นอนและแปลงสตริงย่อยเป็น int ได้อย่างไร


242

ฉันจะใช้สิ่งต่อไปนี้ (Python pseudocode) ใน C ++ ได้อย่างไร

if argv[1].startswith('--foo='):
    foo_value = int(argv[1][len('--foo='):])

(ตัวอย่างเช่นถ้าargv[1]เป็น--foo=98เช่นนั้นfoo_valueคือ98)

อัปเดต:ฉันลังเลที่จะดู Boost เนื่องจากฉันแค่มองการเปลี่ยนแปลงเล็กน้อยเป็นเครื่องมือบรรทัดคำสั่งเล็ก ๆ น้อย ๆ (ฉันไม่ต้องการเรียนรู้วิธีเชื่อมโยงและใช้ Boost สำหรับผู้เยาว์ การเปลี่ยนแปลง)


สิ่งนี้ก็น่าสนใจ
manlio

คำตอบ:


449

ใช้โอเวอร์โหลดrfindที่มีposพารามิเตอร์:

std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) {
  // s starts with prefix
}

ใครต้องการอะไรอีกบ้าง เพียว STL!

หลายคนเข้าใจผิดว่าหมายถึง "ค้นหาย้อนหลังผ่านสตริงทั้งหมดเพื่อค้นหาคำนำหน้า" ที่จะให้ผลลัพธ์ที่ผิด (เช่นstring("tititito").rfind("titi")คืน 2 ดังนั้นเมื่อเทียบกับ== 0จะกลับเท็จ) และมันจะไม่มีประสิทธิภาพ (มองผ่านสตริงทั้งหมดแทนที่จะเป็นเพียงการเริ่มต้น) แต่ไม่ได้ทำเช่นนั้นเพราะผ่านposพารามิเตอร์เป็น0ซึ่ง จำกัด การค้นหาให้จับคู่ที่ตำแหน่งนั้นหรือก่อนหน้าเท่านั้น ตัวอย่างเช่น:

std::string test = "0123123";
size_t match1 = test.rfind("123");    // returns 4 (rightmost match)
size_t match2 = test.rfind("123", 2); // returns 1 (skipped over later match)
size_t match3 = test.rfind("123", 0); // returns std::string::npos (i.e. not found)

32
คำตอบนี้ควรได้รับการโหวตมากที่สุดไม่ใช่การเพิ่ม: D ทำไมต้องใช้ไลบรารีอื่นเมื่อคุณมี STL แล้ว
Iuliu Atudosiei

@ sweisgerber.dev ฉันสับสนในการต่อสู้ครั้งแรกของคุณ ค่าส่งคืนจากfindจะเป็นศูนย์เฉพาะเมื่อtitiอยู่ที่จุดเริ่มต้นของสตริง หากพบที่อื่นคุณจะได้รับค่าตอบแทนที่ไม่เป็นศูนย์และหากไม่พบคุณจะได้รับค่าnposที่ไม่เป็นศูนย์ สมมติว่าฉันถูกฉันต้องการคำตอบนี้เพราะฉันไม่จำเป็นต้องนำสิ่งที่ไม่ได้มาตรฐาน (ใช่ฉันรู้ว่า Boost อยู่ทุกหนทุกแห่งฉันแค่ชอบ core C ++ libs สำหรับสิ่งง่าย ๆ เช่นนี้)
paxdiablo

@paxdiablo: ถูกต้องมันตรวจสอบว่ามันเริ่มต้นด้วยtitiหรือไม่ แต่ส่วนการแปลงหายไป
sweisgerber.dev

2
เรามีหลักฐานว่าสิ่งนี้ได้รับการปรับปรุงในคอมไพเลอร์ส่วนใหญ่หรือไม่ ฉันไม่พบที่อื่นที่กล่าวถึงการเพิ่มประสิทธิภาพ "ค้นหา" หรือ "rfind" เป็นวิธีปฏิบัติทั่วไปตามค่าส่งคืนที่ตรวจสอบ
Superziyi

2
@alcoforado "rfind จะเริ่มจากด้านหลังของสตริง ... " ไม่นั่นใช้ได้กับการโอเวอร์โหลดrfind()ที่ไม่ได้ใช้posพารามิเตอร์เท่านั้น หากคุณใช้โอเวอร์โหลดที่ใช้posพารามิเตอร์ดังนั้นมันจะไม่ค้นหาสตริงทั้งหมดเฉพาะตำแหน่งนั้นและก่อนหน้า (เช่นเดียวfind()กับปกติที่มีposพารามิเตอร์มองในตำแหน่งนั้นหรือใหม่กว่า) ดังนั้นหากคุณผ่านpos == 0ดังที่แสดงในคำตอบนี้แล้วมันจะพิจารณาเฉพาะการจับคู่ที่ตำแหน่งนั้นเท่านั้น นั่นเป็นการอธิบายทั้งคำตอบและความคิดเห็นแล้ว
Arthur Tacca

188

คุณจะทำเช่นนี้:

std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
    foo_value = atoi(arg.substr(prefix.size()).c_str());

กำลังมองหา lib เช่น Boost.ProgramOptions ที่ทำสิ่งนี้เพื่อคุณก็เป็นความคิดที่ดีเช่นกัน


7
ปัญหาที่ใหญ่ที่สุดของสิ่งนี้คือatoi("123xyz")ผลตอบแทน123นั้นในขณะที่ Python int("123xyz")ขว้างข้อยกเว้น
Tom

วิธีแก้ปัญหาที่เราทำได้คือไปที่ sscanf () และเปรียบเทียบผลลัพธ์กับต้นฉบับเพื่อตัดสินใจว่าจะดำเนินการต่อหรือไม่ก็มีข้อยกเว้น
Roopesh Majeti

1
หรือเพียงแค่แทนที่atoiด้วยstrtolหรือstrtollซึ่งช่วยให้เราตรวจสอบเงื่อนไขข้อผิดพลาดในค่าอินพุต
Tom

1
นี่เป็นทางออกที่ดีกว่าวิธีที่ดีrfindที่สุดซึ่งขึ้นอยู่กับการเพิ่มประสิทธิภาพในการทำงาน
Calmarius

143

เพื่อความสมบูรณ์ฉันจะพูดถึงวิธีการทำ C:

ถ้าstrเป็นสตริงเดิมของคุณsubstrคือสตริงย่อยที่คุณต้องการตรวจสอบแล้ว

strncmp(str, substr, strlen(substr))

จะกลับมา0ถ้าเริ่มต้นด้วยstr substrฟังก์ชั่นstrncmpและstrlenอยู่ในไฟล์ส่วนหัว C<string.h>

(โพสต์ครั้งแรกโดย Yaseen Rauf ที่นี่เพิ่มมาร์กอัป)

สำหรับการเปรียบเทียบกรณีตายใช้แทนstrnicmpstrncmp

นี่คือวิธีการทำ C สำหรับสตริง C ++ คุณสามารถใช้ฟังก์ชั่นเดียวกันนี้:

strncmp(str.c_str(), substr.c_str(), substr.size())

9
แน่นอนว่าทุกคนดูเหมือนจะไป "ใช้เพิ่ม" และฉันหนึ่งขอบคุณสำหรับรุ่นห้องสมุด stl หรือ OS
Force Gaia

ใช่. อย่างไรก็ตามมันจะถือว่าสตริงนั้นไม่มีอักขระเป็นโมฆะ ถ้ามันไม่ได้เป็นกรณี - หนึ่งควรใช้memcmp()
Avishai Y

ทำไมทุกคนจะใช้อะไรนอกเหนือจากโซลูชันที่สวยงามเรียบง่ายนี้
Adam Zahran

88

หากคุณใช้ Boost อยู่แล้วคุณสามารถทำได้ด้วยการเพิ่มอัลกอริธึมสตริง + เพิ่ม lexical cast:

#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>

try {    
    if (boost::starts_with(argv[1], "--foo="))
        foo_value = boost::lexical_cast<int>(argv[1]+6);
} catch (boost::bad_lexical_cast) {
    // bad parameter
}

วิธีการเช่นนี้เหมือนกับคำตอบอื่น ๆ ที่ให้ไว้ที่นี่ก็โอเคสำหรับงานง่าย ๆ แต่ในระยะยาวคุณมักจะใช้ห้องสมุดแยกบรรทัดคำสั่งดีกว่า Boost มีหนึ่งรายการ ( Boost.Program_options ) ซึ่งอาจเหมาะสมถ้าคุณบังเอิญใช้ Boost อยู่แล้ว

มิฉะนั้นการค้นหา "c ++ บรรทัดคำสั่ง parser" จะให้ตัวเลือกจำนวนมาก


107
การดึงการอ้างอิงจำนวนมากสำหรับการตรวจสอบคำนำหน้าสตริงเหมือนกับการยิงนกด้วยศีล
Tobi

150
"Use Boost" เป็นคำตอบที่ผิดเสมอเมื่อมีคนถามถึงวิธีการดำเนินการกับสตริงอย่างง่าย ๆ ใน C ++
Glenn Maynard

90
ลบ 1 สำหรับแนะนำ Boost
uglycoyote

37
การใช้การเพิ่มที่นี่ถูกต้องถ้าคุณใช้การเพิ่มในโครงการของคุณ
Alex Che

17
คำตอบจะขึ้นต้นด้วย "ถ้าคุณใช้ Boost ... " เห็นได้ชัดว่านี่คือคำตอบที่ถูกต้อง "... หากคุณใช้ Boost" ถ้าไม่ดูข้อเสนอแนะโดย @Thomas
NuSkooler

82

รหัสฉันใช้เอง:

std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
    std::string argumentValue = argument.substr(prefix.size());
}

2
รัดกุมมากที่สุดและขึ้นอยู่กับสตริง std :: ยกเว้นเอาอาร์กิวเมนต์เสริมและทำให้เข้าใจผิดขนาด () ในตอนท้ายของ substr สุดท้าย
Ben Bryant

@ ben-bryant: ขอบคุณสำหรับหัวขึ้น ไม่ทราบว่าเป็นตัวเลือก
HüseyinYağlı

16
การใช้substrโอกาสในการทำสำเนาที่ไม่จำเป็น str.compare(start, count, substr)วิธีการที่ใช้ในการตอบของโทมัสมีประสิทธิภาพมากขึ้น คำตอบ razvanco13 ของstd::equalมีวิธีการที่จะหลีกเลี่ยงการคัดลอกโดยใช้
Felix Dombek

4
@ HüseyinYağlı Thomas uses atoi which is only for windowsหือ? atoiได้รับฟังก์ชั่นห้องสมุดมาตรฐาน C มาตั้งแต่ ... เคย ในความเป็นจริงatoiมันไม่ดี - ไม่ใช่เพราะเฉพาะ Windows แต่เพราะ (1) C ไม่ใช่ C ++ และ (2) เลิกใช้แล้วแม้ใน C (คุณควรใช้strtolหรือฟังก์ชันอื่นที่เกี่ยวข้องเนื่องจากatoiมี ไม่มีการจัดการข้อผิดพลาด แต่มีเพียงใน C เท่านั้น)
คู่ปรับ Shot

50

ยังไม่มีใครใช้อัลกอริทึม STL /ฟังก์ชั่นที่ไม่ตรงกัน ถ้าสิ่งนี้คืนค่าจริงคำนำหน้าเป็นคำนำหน้า 'toCheck':

std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()

prog ตัวอย่างเต็มรูปแบบ:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
                  << "Will print true if 'prefix' is a prefix of string" << std::endl;
        return -1;
    }
    std::string prefix(argv[1]);
    std::string toCheck(argv[2]);
    if (prefix.length() > toCheck.length()) {
        std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
                  << "'prefix' is longer than 'string'" <<  std::endl;
        return 2;
    }
    if (std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()) {
        std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck << '"' << std::endl;
        return 0;
    } else {
        std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"' << toCheck << '"' << std::endl;
        return 1;
    }
}

แก้ไข:

ดังที่ @James T. Huggett แนะนำ std :: equal เป็นแบบที่ดีกว่าสำหรับคำถาม: A เป็นส่วนนำหน้าของ B หรือไม่ และเป็นรหัสที่สั้นกว่าเล็กน้อย:

std::equal(prefix.begin(), prefix.end(), toCheck.begin())

prog ตัวอย่างเต็มรูปแบบ:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char **argv) {
  if (argc != 3) {
    std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
              << "Will print true if 'prefix' is a prefix of string"
              << std::endl;
    return -1;
  }
  std::string prefix(argv[1]);
  std::string toCheck(argv[2]);
  if (prefix.length() > toCheck.length()) {
    std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
              << "'prefix' is longer than 'string'" << std::endl;
    return 2;
  }
  if (std::equal(prefix.begin(), prefix.end(), toCheck.begin())) {
    std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck
              << '"' << std::endl;
    return 0;
  } else {
    std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"'
              << toCheck << '"' << std::endl;
    return 1;
  }
}

2
ทำไมไม่ใช้ std :: เท่ากับ?
Brice M. Dempsey

ฟังดูดีสำหรับฉัน. มันจะเป็นรหัสที่สั้นลงเช่นกัน ฉัน spose ฉันจะต้องแก้ไขคำตอบตอนนี้: p
matiu

2
การใช้std::equalสตริงมีข้อเสียที่ตรวจไม่พบจุดสิ้นสุดของสตริงดังนั้นคุณต้องตรวจสอบด้วยตนเองว่าคำนำหน้านั้นสั้นกว่าทั้งสตริงหรือไม่ (ทำในฐานะที่ถูกต้องในตัวอย่าง PROG แต่มองข้ามในหนึ่งซับข้างต้น.)
เฟลิกซ์ Dombek

ดังนั้นไม่มีประโยชน์กับ rfind?
АндрейВахрушев

26

เนื่องจากทั้งสตริง - argv[1]และ"--foo"- เป็นสตริง C คำตอบของ @ FelixDombekจึงเป็นทางออกที่ดีที่สุด

อย่างไรก็ตามเมื่อเห็นคำตอบอื่น ๆ ฉันคิดว่ามันควรค่าแก่การสังเกตว่าถ้าข้อความของคุณพร้อมใช้งานแล้ว a std::stringแล้วมีวิธีแก้ปัญหาที่ง่ายและไม่มีประสิทธิภาพสูงสุดซึ่งไม่ได้กล่าวถึง:

const char * foo = "--foo";
if (text.rfind(foo, 0) == 0)
    foo_value = text.substr(strlen(foo));

และถ้า foo เป็นสตริงอยู่แล้ว:

std::string foo("--foo");
if (text.rfind(foo, 0) == 0)
    foo_value = text.substr(foo.length());

6
rfind(x, 0) == 0ควรกำหนดไว้ในมาตรฐานอย่างstarts_with
แท้จริง

1
ไม่เพราะrfind()(แทนstartswith()) ไม่มีประสิทธิภาพมาก - มันทำการค้นหาจนถึงจุดสิ้นสุดของสตริง
ankostis

4
@ankostis rfind (x) ค้นหาจากจุดสิ้นสุดจนถึงจุดเริ่มต้นจนกระทั่งพบว่า x แน่นอน แต่ rfind (x, 0) เริ่มค้นหาตั้งแต่เริ่มต้น (ตำแหน่ง = 0) จนถึงจุดเริ่มต้น ดังนั้นจะค้นหาเฉพาะที่ที่ต้องการค้นหาเท่านั้น ไม่ค้นหาจาก / จนจบ
คนขี้ขลาดนิรนาม

18

ด้วย C ++ 17 คุณสามารถใช้std::basic_string_view& กับ C ++ 20 std::basic_string::starts_withหรือstd::basic_string_view::starts_withหรือ

ประโยชน์ของstd::string_viewการเปรียบเทียบstd::string- เกี่ยวกับการจัดการหน่วยความจำ - คือมันเก็บตัวชี้ไปที่ "สตริง" เท่านั้น (ลำดับที่ต่อเนื่องกันของวัตถุที่มีลักษณะคล้ายถ่าน) และรู้ขนาดของมัน ตัวอย่างโดยไม่ย้าย / คัดลอกสตริงต้นทางเพียงเพื่อรับค่าจำนวนเต็ม:

#include <exception>
#include <iostream>
#include <string>
#include <string_view>

int main()
{
    constexpr auto argument = "--foo=42"; // Emulating command argument.
    constexpr auto prefix = "--foo=";
    auto inputValue = 0;

    constexpr auto argumentView = std::string_view(argument);
    if (argumentView.starts_with(prefix))
    {
        constexpr auto prefixSize = std::string_view(prefix).size();
        try
        {
            // The underlying data of argumentView is nul-terminated, therefore we can use data().
            inputValue = std::stoi(argumentView.substr(prefixSize).data());
        }
        catch (std::exception & e)
        {
            std::cerr << e.what();
        }
    }
    std::cout << inputValue; // 42
}

1
@RolandIllig ไม่std::atoiเป็นเรื่องปกติอย่างสมบูรณ์ มันจะโยนข้อยกเว้นเกี่ยวกับการป้อนข้อมูลที่ไม่ดี (ซึ่งมีการจัดการในรหัสนี้) คุณมีอย่างอื่นในใจหรือไม่?
Roi Danton

คุณกำลังพูดถึงatoiจาก<cstdlib>? เอกสารกล่าวว่า "มันไม่เคยโยนข้อยกเว้น"
Roland Illig

@RolandIllig ฉันหมายถึงความคิดเห็นแรกของคุณ ดูเหมือนว่าคุณกำลังเข้าใจผิดเกี่ยวกับการพูดคุยแทนatoi std::atoiอันแรกไม่ปลอดภัยที่จะใช้ในขณะที่หลังเป็นเรื่องปกติ ฉันใช้อันหลังในรหัสที่นี่
Roi Danton

โปรดพิสูจน์ให้ฉันเห็นว่าstd::atoiมีข้อผิดพลาดเกิดขึ้นจริงโดยอ้างการอ้างอิงที่เหมาะสม จนกว่าคุณจะทำฉันไม่เชื่อว่าคุณจะสับสนและมีทั้งสองอย่าง::atoiและstd::atoiแสดงออกในทางที่แตกต่างไปจากเดิมอย่างสิ้นเชิง
Roland Illig

4
@RolandIllig ขอบคุณที่อดทน! คุณกำลังที่เหมาะสมก็คือการกำกับดูแลที่ ถูกนำมาใช้แทนstd::atoi std::stoiฉันได้แก้ไขแล้ว
Roi Danton

12
text.substr(0, start.length()) == start

3
@ GregorDoroschenko มันจะตอบ "ตรวจสอบว่าสตริงเริ่มต้นด้วยส่วนอื่น"
etarion

1
มีประสิทธิภาพและสวยงามโดยใช้สตริง :: ฉันเรียนรู้มากที่สุดจากสิ่งนี้
Michael B

1
คะแนนพิเศษสำหรับการเป็นสายการบินเดียวที่เหมาะสำหรับใช้กับif (one-liner)
Adam.at.Epsilon

@Roland Illig ทำไมคุณถึงเชื่อว่าพฤติกรรมในกรณีนั้นไม่ได้กำหนดไว้? นิพจน์จะคืนค่าเท็จเนื่องจาก substr ส่งคืนสตริงที่มีความยาวเท่ากับข้อความตามen.cppreference.com/w/cpp/string/basic_string/substr
Macsinus

11

การใช้ STL อาจมีลักษณะดังนี้:

std::string prefix = "--foo=";
std::string arg = argv[1];
if (prefix.size()<=arg.size() && std::equal(prefix.begin(), prefix.end(), arg.begin())) {
  std::istringstream iss(arg.substr(prefix.size()));
  iss >> foo_value;
}

2
if (prefix.size()<=arg.size() && std::equal(...))ที่ควรจะเป็น
Jared Grubb

10

ด้วยความเสี่ยงที่จะถูกไล่ออกเพราะใช้งานโครงสร้าง C ฉันคิดว่าsscanfตัวอย่างนี้ดูดีกว่าโซลูชัน Boost ส่วนใหญ่ และคุณไม่ต้องกังวลกับการเชื่อมโยงหากคุณทำงานที่ใดก็ได้ที่มี Python interpreter!

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    for (int i = 1; i != argc; ++i) {
        int number = 0;
        int size = 0;
        sscanf(argv[i], "--foo=%d%n", &number, &size);
        if (size == strlen(argv[i])) {
            printf("number: %d\n", number);
        }
        else {
            printf("not-a-number\n");
        }
    }
    return 0;
}

นี่คือตัวอย่างผลลัพธ์ที่แสดงให้เห็นถึงวิธีการแก้ปัญหาการจัดการขยะมูลฝอยชั้นนำ / ต่อท้ายอย่างถูกต้องเช่นเดียวกับรหัสงูหลามที่เทียบเท่าและมีความถูกต้องมากกว่าสิ่งที่ใช้atoi(ซึ่งจะไม่สนใจคำต่อท้ายที่ไม่ใช่ตัวเลข)

$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2'
number: 2
not-a-number
not-a-number
not-a-number

7
ถ้าargv[i]เป็น"--foo=9999999999999999999999999"เช่นนั้นพฤติกรรมนั้นไม่ได้กำหนดไว้ (แม้ว่าการใช้งานส่วนใหญ่หรือทั้งหมดควรประพฤติตนอย่างมีสติ) 9999999999999999999999999 > INT_MAXฉันสมมติ
Keith Thompson

10

ฉันใช้std::string::compareวิธีการห่อหุ้มด้วยยูทิลิตี้ดังนี้:

static bool startsWith(const string& s, const string& prefix) {
    return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}

5

ทำไมไม่ใช้ gnu getopts นี่เป็นตัวอย่างพื้นฐาน (ไม่มีการตรวจสอบความปลอดภัย):

#include <getopt.h>
#include <stdio.h>

int main(int argc, char** argv)
{
  option long_options[] = {
    {"foo", required_argument, 0, 0},
    {0,0,0,0}
  };

  getopt_long(argc, argv, "f:", long_options, 0);

  printf("%s\n", optarg);
}

สำหรับคำสั่งต่อไปนี้:

$ ./a.out --foo=33

คุณจะได้รับ

33

5

ในกรณีที่คุณต้องการความเข้ากันได้ของ C ++ 11 และไม่สามารถใช้บูสต์ได้นี่เป็นตัวอย่างการใช้งานบูสต์ที่รองรับ:

#include <iostream>
#include <string>

static bool starts_with(const std::string str, const std::string prefix)
{
    return ((prefix.size() <= str.size()) && std::equal(prefix.begin(), prefix.end(), str.begin()));
}

int main(int argc, char* argv[])
{
    bool usage = false;
    unsigned int foos = 0; // default number of foos if no parameter was supplied

    if (argc > 1)
    {
        const std::string fParamPrefix = "-f="; // shorthand for foo
        const std::string fooParamPrefix = "--foo=";

        for (unsigned int i = 1; i < argc; ++i)
        {
            const std::string arg = argv[i];

            try
            {
                if ((arg == "-h") || (arg == "--help"))
                {
                    usage = true;
                } else if (starts_with(arg, fParamPrefix)) {
                    foos = std::stoul(arg.substr(fParamPrefix.size()));
                } else if (starts_with(arg, fooParamPrefix)) {
                    foos = std::stoul(arg.substr(fooParamPrefix.size()));
                }
            } catch (std::exception& e) {
                std::cerr << "Invalid parameter: " << argv[i] << std::endl << std::endl;
                usage = true;
            }
        }
    }

    if (usage)
    {
        std::cerr << "Usage: " << argv[0] << " [OPTION]..." << std::endl;
        std::cerr << "Example program for parameter parsing." << std::endl << std::endl;
        std::cerr << "  -f, --foo=N   use N foos (optional)" << std::endl;
        return 1;
    }

    std::cerr << "number of foos given: " << foos << std::endl;
}

2

คุณยังสามารถใช้strstr:

if (strstr(str, substr) == substr) {
    // 'str' starts with 'substr'
}

แต่ฉันคิดว่ามันดีสำหรับสตริงสั้น ๆ เท่านั้นเพราะมันต้องวนซ้ำทั้งสตริงเมื่อสตริงไม่ได้ขึ้นต้นด้วย 'substr'


2

โอเคทำไมการใช้ห้องสมุดและสิ่งของต่าง ๆ มีความซับซ้อน? อ็อบเจกต์ C ++ String โอเวอร์โหลดตัวดำเนินการ [] ดังนั้นคุณสามารถเปรียบเทียบ chars .. เหมือนที่ฉันเพิ่งทำเพราะฉันต้องการแสดงรายการไฟล์ทั้งหมดในไดเรกทอรีและไม่สนใจไฟล์ที่มองไม่เห็นและ .. และ pseudofiles

while ((ep = readdir(dp)))
{
    string s(ep->d_name);
    if (!(s[0] == '.')) // Omit invisible files and .. or .
        files.push_back(s);
}

มันง่ายมาก ..


4
บทเรียนในประวัติศาสตร์: plus.sandbox.google.com/+RobPikeTheHuman/posts/R58WgWwN9jp
robertwb

2
@robertwb Google+ ไม่สามารถใช้ได้อีกต่อไป
_Static_assert

0
std::string text = "--foo=98";
std::string start = "--foo=";

if (text.find(start) == 0)
{
    int n = stoi(text.substr(start.length()));
    std::cout << n << std::endl;
}

3
มันจะดีมากถ้าคุณหลีกเลี่ยงการวางโค้ดโดยไม่มีคำอธิบายรหัส ขอบคุณ.
เกิดใหม่

1
รหัสที่ไม่มีประสิทธิภาพจะทำการค้นหาต่อไปตั้งแต่เริ่มต้นของสตริง
ankostis

0

ด้วย C ++ 11 หรือสูงกว่าคุณสามารถใช้find()และfind_first_of()

ตัวอย่างการใช้ find เพื่อค้นหา char ตัวเดียว:

#include <string>
std::string name = "Aaah";
size_t found_index = name.find('a');
if (found_index != std::string::npos) {
    // Found string containing 'a'
}

ตัวอย่างการใช้ find เพื่อค้นหาสตริงแบบเต็ม & เริ่มจากตำแหน่งที่ 5:

std::string name = "Aaah";
size_t found_index = name.find('h', 3);
if (found_index != std::string::npos) {
    // Found string containing 'h'
}

ตัวอย่างการใช้find_first_of()อักขระเฉพาะและตัวแรกเพื่อค้นหาที่เริ่มต้นเท่านั้น:

std::string name = ".hidden._di.r";
size_t found_index = name.find_first_of('.');
if (found_index == 0) {
    // Found '.' at first position in string
}

โชคดี!


ทำไมไม่ rfind rfind (str, 0) จะไม่จำเป็นต้องสแกนสตริงทั้งหมดเพื่อทำการเลือกเนื่องจากไม่สามารถเลื่อนได้ ดูคนอื่น ๆ
user2864740

0

เนื่องจาก C ++ 11 std::regex_searchยังสามารถใช้เพื่อให้การจับคู่นิพจน์ที่ซับซ้อนยิ่งขึ้น ตัวอย่างต่อไปนี้จะจัดการกับตัวเลขลอยตัวstd::stofและหลังจากintนั้น

อย่างไรก็ตามparseIntวิธีการที่แสดงด้านล่างอาจทำให้เกิดstd::invalid_argumentข้อยกเว้นหากคำนำหน้าไม่ตรงกัน สามารถปรับเปลี่ยนได้ง่ายขึ้นอยู่กับแอปพลิเคชันที่กำหนด:

#include <iostream>
#include <regex>

int parseInt(const std::string &str, const std::string &prefix) {
  std::smatch match;
  std::regex_search(str, match, std::regex("^" + prefix + "([+-]?(?=\\.?\\d)\\d*(?:\\.\\d*)?(?:[Ee][+-]?\\d+)?)$"));
  return std::stof(match[1]);
}

int main() {
    std::cout << parseInt("foo=13.3", "foo=") << std::endl;
    std::cout << parseInt("foo=-.9", "foo=") << std::endl;
    std::cout << parseInt("foo=+13.3", "foo=") << std::endl;
    std::cout << parseInt("foo=-0.133", "foo=") << std::endl;
    std::cout << parseInt("foo=+00123456", "foo=") << std::endl;
    std::cout << parseInt("foo=-06.12e+3", "foo=") << std::endl;

//    throw std::invalid_argument
//    std::cout << parseInt("foo=1", "bar=") << std::endl;

    return 0;
}

ชนิดของความมหัศจรรย์ของรูปแบบการ regex รายละเอียดได้ดีในต่อไปนี้คำตอบ

แก้ไข:คำตอบก่อนหน้านี้ไม่ได้ทำการแปลงเป็นจำนวนเต็ม


0

เริ่มต้นด้วย C ++ 20 คุณสามารถใช้starts_withวิธีนี้ได้

std::string s = "abcd";
if (s.starts_with("abc")) {
    ...
}

-3
if(boost::starts_with(string_to_search, string_to_look_for))
    intval = boost::lexical_cast<int>(string_to_search.substr(string_to_look_for.length()));

นี่คือการทดสอบอย่างสมบูรณ์ หลักการนั้นเหมือนกับ Python ต้องใช้ Boost.StringAlgo และ Boost.LexicalCast

ตรวจสอบว่าสตริงเริ่มต้นด้วยสตริงอื่นแล้วรับซับสตริง ('slice') ของสตริงแรกแล้วแปลงเป็นสตริงใช้คำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.