2012-03-06 25 views
2

我有這段代碼。當時並不明顯,但由於「fc」和「fcip」都以「fc」開頭,因此寫入的代碼總是會選擇第一個選項。String StartsWith()任何避免2次檢查的方法?

string fcportdelimit = "fc"; 
string fcipportdelimit = "fcip"; 

if (BlockToProcess[0].StartsWith(fcportdelimit)) 
{ 
    try 
    { 
     this.ParseFCInterface(BlockToProcess); 
    } 
    catch (Exception E) 
    { 
     throw; 
    } 
} 
else if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
{ 
    try 
    { 
     this.ParseFCIPInterface(BlockToProcess); 
    } 
    catch (Exception E) 
    { 
     throw; 
    } 
} 

我查看了字符串類,但沒有看到將模式作爲輸入的StartsWith()或Contains()。我正在測試的字符串要麼是一個patttern fcN/N,要麼是fcipN,其中N是一個數字。所以,我想我必須做這樣的事情?

if (BlockToProcess[0].StartsWith(fcportdelimit || fcipportdelimit) 
{ 
    if (BlockToProcess[0].StartsWith(fcipportdelimit) 
    { 
     // do something here 
    } 
    else 
    { 
     //since fcipportdelimit didn't match it must be an fcport 
     //so do something else 
    } 
} 
+0

'StartsWith(fcportdelimit || fcipportdelimit)'是有效的語法很遠...... – 2012-03-06 17:57:17

+0

聽起來像是正是這類問題該正則表達式的是。也許看看他們。 – 2012-03-06 17:59:10

+0

你考慮過正則表達式匹配嗎? – Brettski 2012-03-06 17:59:42

回答

6

鑑於StartsWith("fcip")意味着StartsWith("fc"),只是先測試後者,並嵌套第二個測試。

此外,您的try塊是完全冗餘和不起作用。

if (BlockToProcess[0].StartsWith(fcportdelimit) { 
    if (BlockToProcess[0].StartsWith(fcipportdelimit) { 
     // do something here 
    } 
    else { 
     // do something here 
    } 
} 

(當然,第二次檢查仍含有多餘的部分,因爲它會檢查fc再次重構,但該檢查只是使代碼的可讀性變差並不見得會受益的性能。)

+0

這是我採取的方法。我不想這麼輕易放棄 - 我認爲可能有一種字符串的方法,我不知道它會做我想要的。 – 2012-03-06 19:44:06

7

我覺得正則表達式很容易。下面是Regex.IsMatch一個例子:

if (Regex.IsMatch(str, "^(?:fc|fcip)") { 
    ... 
} 

^說「錨到開始」(或,「打頭」),則|說「非此即彼」,並且(?:...)爲分組。

但是,由於每個匹配調用兩種不同的方法,爲什麼不讓它像它一樣呢?我已經刪除了額外的代碼,使其更易於查看。

Konrad指出,條件的訂單是重要的。

var command = BlockToProcess[0]; 
if (command.StartsWith("fcip")) { 
    this.ParseFCIPInterface(BlockToProcess); // ParseFCIP 
} else if (command.StartsWith("fc") { 
    this.ParseFCInterface(BlockToProcess); // ParseFC 
} 

快樂編碼。

+1

但是,你仍然*需要確定哪些匹配(你*可以*使用正則表達式,但你的代碼沒有說明這一點)。而你的第二個代碼不會*使用第二個分支 - 你需要反轉條件。 – 2012-03-06 18:02:43

+0

@KonradRudolph的確,我錯過了:更新的迴應。 – 2012-03-06 18:03:18

+0

爲什麼在正則表達式中使用非捕獲組?捕獲組在這裏沒有用於任何東西,所以如果你把它們放在正則表達式中並不重要。 – svick 2012-03-06 18:05:45

0

怎麼樣?

BlockToProcess[0].StartsWith(fcportdelimit) || BlockToProcess[0].StartsWith(fcipportdelimit) 
1

有什麼不妥做兩個比較,像這樣的:

if (BlockToProcess[0].StartsWith(fcportdelimit) 
    || BlockToProcess[0].StartsWith(fcipportdelimit)) 
{ 
    if (BlockToProcess[0].StartsWith(fcipportdelimit) 
    { 
    // do something here 
    } 
    else 
    { //since fcipportdelimit didn't match it must be an fcport 
     //so do something else 
    } 
} 
1

只需將其更改爲:

if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
{ 
} 
else if (BlockToProcess[0].StartsWith(fcportdelimit)) 
{ 
} 

和至少你有一些作品。效率在這裏似乎不成問題。

0

我對測試字符串是否將是一個patttern FCN/N 或fcipN

所以,從邏輯上,你只需要進行一個測試。如果不以「FCIP」開始,那麼它必須只是開始「FC」

string fcipportdelimit = "fcip"; 
try 
{ 
    if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
    { 
     this.ParseFCIPInterface(BlockToProcess); 
    } 
    else 
    { 
     this.ParseFCInterface(BlockToProcess); 
    } 
} 
catch (Exception E) 
{ 
    throw; 
} 
0

這個答案很可能矯枉過正,但應該產生一個更易於維護的&檢驗的解決方案。它還需要一些相當先進的重構測試來保持現有的行爲。

這裏的一般想法是,您提供的代碼意味着單個解析類可能對各個操作知之甚多。鑑於此,我最初將創建一個IParser接口兩個實現。

public interface IParser 
{ 
    void Parse(string input); 
    string RequiredPrefix { get; } 

    /* you'll want to add anything that's appropriate for your code here */ 
} 

public class FcPortParser : IParser { ... } 
public class FcipPortParser : IParser { ... } 

然後創建一個工廠,返回相應的解析器給定的輸入:

public class ParserFactory 
{ 
    private List<IParser> _knownParsers; 

    public ParserFactory() 
    { 
     // you should be able to initialize this dynamically but that's off-topic here 
     _knownParsers = new List<IParser> { new FcPortParser(), new FcipPortParser() }; 
    } 

    public IParser GetFromString(string given) 
    { 
     // return the IParser with the longest prefix that given starts with 
     // this will return null for a non-match 
     return _knownParsers.Where(p => given.StartsWith(p.RequiredPrefix)) 
          .OrderByDescending(p => p.RequiredPrefix.Length) 
          .FirstOrDefault(); 
    } 
} 

有了這個解決方案,您可以輕鬆地測試各個分析器以及工廠返回一個合適的。

//NUnit 
Assert.IsInstanceOf<FcipPortParser>(factory.GetFromString("fcip...")); 
Assert.IsInstanceOf<FcPortParser>(factory.GetFromString("fc...")); 
Assert.IsNull(factory.GetFromString("undefined...")); 

...現在你的代碼變得這樣:

var parser = _factory.GetFromString(BlockToProcess[0]); 
if (parser != null) 
{ 
    parser.Parse(BlockToProcess[0]); 
} 

如果你想避免parser != null檢查,您可以添加像這樣的一個空對象實現(並確保出廠精選它):

public class NullParser : IParser 
{ 
    public void Parse(string given) { /* do nothing */ } 
    // should return true for every non-null string 
    public string RequiredPrefix { get { return string.Empty; } } 
} 

現在,當您需要添加功能,你只需要添加一個新的IParser類(和,如果工廠沒有動態初始化,工廠)。

public class FcNewParser : IParser 
{ 
    public void Parse(string given) { ... } 
    public string RequiredPrefix { get { return "fcnew"; } } 
} 
0

按照相反順序執行,首先檢查fcipportdelimit,然後檢查else塊中的fcportdelimit。這將解決您的問題

string fcportdelimit = "fc"; 
string fcipportdelimit = "fcip"; 

if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
         { 
          try 
          { 
           this.ParseFCInterface(BlockToProcess); 
          } 
          catch (Exception E) 
          { 
           throw; 
          } 
         } 
         else if (BlockToProcess[0].StartsWith(fcportdelimit)) 
         { 
          try 
          { 
           this.ParseFCIPInterface(BlockToProcess); 
          } 
          catch (Exception E) 
          { 
           throw; 
          } 
         }