Coder Social home page Coder Social logo

whisperfish / rust-phonenumber Goto Github PK

View Code? Open in Web Editor NEW
143.0 8.0 50.0 3.9 MB

Library for parsing, formatting and validating international phone numbers.

License: Apache License 2.0

Rust 99.72% Shell 0.28%
rust rust-library parser formatter validator phone-number

rust-phonenumber's Introduction

phonenumber

CI Build Crates.io phonenumber License

Rust version of libphonenumber. We currently require 1.58.0 as minimum supported Rust version (MSRV).

Usage

Add this to your Cargo.toml:

[dependencies]
phonenumber = "0.3"

Example

The following example parses, validates and formats the given phone number.

use phonenumber::Mode;
use std::env;

fn main() {
	let mut args = env::args().skip(1).collect::<Vec<_>>();

	if args.len() < 1 {
		panic!("not enough arguments");
	}

	let number  = args.pop().unwrap();
	let country = args.pop().map(|c| c.parse().unwrap());

	let number = phonenumber::parse(country, number).unwrap();
	let valid  = phonenumber::is_valid(&number);

	if valid {
		println!("\x1b[32m{:#?}\x1b[0m", number);
		println!();
		println!("International: {}", number.format().mode(Mode::International));
		println!("     National: {}", number.format().mode(Mode::National));
		println!("      RFC3966: {}", number.format().mode(Mode::Rfc3966));
		println!("        E.164: {}", number.format().mode(Mode::E164));
	}
	else {
		println!("\x1b[31m{:#?}\x1b[0m", number);
	}
}

rust-phonenumber's People

Contributors

adamchalmers avatar ds-cbo avatar dvazar avatar eijebong avatar fabricedesre avatar gferon avatar guillaumegomez avatar meh avatar pickfire avatar regismesquita avatar rubdos avatar rustonaut avatar ta3pks avatar tom25519 avatar yannleretaille avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-phonenumber's Issues

[EDIT: rq. impl isNumberMatch] Equivalent `PhoneNumber`s are not equal if the source of their country code is different

Because Eq is derived for PhoneNumber, this happens:

let full = "+1-800-555-1234".parse().unwrap();
let equivalent = `phonenumber::parse(Some(phonenumber::country::US), "800-555-1234").unwrap();

// false
full == equivalent;

phonenumber::country::Code stores the u16 as well as the phonenumber::country::Source that indicates where it came from. I can see how this may be useful for some aspects of a program's logic, but it makes straightforward equality checks of normalized PhoneNumbers awkward (requiring a helper function or a newtype).

I just wanted to draw attention to this. Maybe it's the desired behavior? Maybe this is how libphonenumber works? From my perspective, though, it violates the "Principle of Least Surprise".

Compile warnings

Cargo.toml: version requirement 0.3.1+8.12.9 for dependency phonenumber includes semver metadata which will be ignored, removing the metadata is recommended to avoid confusion

Phone Number Parse Fail

I tried to parse "+1 520-878-2491" but it fails at parsing with an invalid country code.

The Java and JavaScript libphonenumber do parse this correctly, and slight variations in this also parse correctly (e.g. "+1 520 878 2491" parses correctly).

Use more compact and easier to decode metadata.

It might be a good idea to convert the XML files into bincode in the build.rs and then just deserialize it at runtime.

Need to find a way to share the code that actually parses the XML and generates the temporary data structures between the build.rs and the actual code, it may require splitting that code in another crate.

Move `database.bin` generation to an `xtask`

The database.bin is currently generated in the build.rs.
This is unnecessary and has a few downsides.

  • The database.bin only needs to be generated when the assets/PhoneNumberMetadata.xml is updated.
  • build.rs files can be seen as suspicious. A build.rs file executing on my local machine may be outside of the risks I'm willing to take
  • The dependencies used in build.rs are required to build the project.

I propose that the generation of database.bin is moved into an xtask.

cargo-xtask is way to add free-form automation to a Rust project, a-la make, npm run or bespoke bash scripts.

The two distinguishing features of xtask are:

It doesn't require any other binaries besides cargo and rustc, it fully bootstraps from them
Unlike bash, it can more easily be cross platform, as it doesn't use the shell.

This means restructuring the project into a workspace where one of the members is the xtask package.
But the benefits are:

  • The xtask is independent from the published package
    • When it's run is independent, it only needs to be run manually when assets/PhoneNumberMetadata.xml is updated.
    • it's dependencies are independent, the published package has fewer dependencies
    • There's no need for a build.rs anymore

Lazily create regular expressions.

Currently 60/70% of the really slow initialization time is spent compiling regular expressions which may never be used, lazily creating them might be a good idea.

Make sure you can detect country code by phone number.

  • There was a now out of sync PR #5
  • There was a local implementation which might or might not have merged.
  • There might or might not be further problems

So:

  • check what the current state is
  • after refactoring this crate see how the feature can be implemented if missing

[BUG] The library panicked over a specific combination of country and phone number

Library version: phonenumber-0.3.1+8.12.9
How to reproduce:

use phonenumber::country::Id;


fn main() {
    if let Ok(pn) = phonenumber::parse(Some(Id::CH), "003-836-4618x3001") {
        phonenumber::is_valid(&pn);
    }

    ()
}

Stack backtrace:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', /home/adv/.cargo/registry/src/github.com-1ecc6299db9ec823/phonenumber-0.3.1+8.12.9/src/validator.rs:173:49
stack backtrace:
   0: rust_begin_unwind
             at /rustc/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/std/src/panicking.rs:495:5
   1: core::panicking::panic_fmt
             at /rustc/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/core/src/panicking.rs:92:14
   2: core::option::expect_none_failed
             at /rustc/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/core/src/option.rs:1268:5
   3: core::result::Result<T,E>::unwrap
             at /home/adv/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:973:23
   4: phonenumber::validator::source_for
             at /home/adv/.cargo/registry/src/github.com-1ecc6299db9ec823/phonenumber-0.3.1+8.12.9/src/validator.rs:173:21
   5: phonenumber::validator::is_valid_with
             at /home/adv/.cargo/registry/src/github.com-1ecc6299db9ec823/phonenumber-0.3.1+8.12.9/src/validator.rs:112:33
   6: phonenumber::validator::is_valid
             at /home/adv/.cargo/registry/src/github.com-1ecc6299db9ec823/phonenumber-0.3.1+8.12.9/src/validator.rs:105:2
   7: pyphonenumber::main
             at ./src/main.rs:6:9
   8: core::ops::function::FnOnce::call_once
             at /home/adv/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Why is 3.0 not on github?

A new version of this crate was released about 4 days ago, but the source code and changes are not available here.

Did you not intend to push the release?

Returning `failure::Error` in `parse` function

In the current implementation of the parse function a failure::Error wrapping a crate::error::Parse. Since the Parse struct already derives the Fail trait it seems to me redundant to do this manual wrapping. Additionally by doing this manual wrapping people cannot handle the raw Parse error in their code.

00-prefixed international numbers don't parse

let n = "0032474123456";
assert!(phonenumber::parse(None, n).is_ok());

I would expect this to yield +32474123456, but it seemingly does not: it yields InvalidCountryCode (which could've parsed as Belgium instead).

Loading default `DATABASE` is extremely slow in WASM

For some reason, the initial deref of the lazy_static takes several seconds, locking up the page while the first phone number is either parsed or formatted. After that, it's really snappy. Using the Chrome Dev Tools profiler, it looks like the bincode deserializing only takes ~40ms and most of the time is spent in Database::from. The callgraph is dominated by closure calls. I can only guess that the WASM backend can't optimize away all the closures as aggressively as the x86 one can?
Screenshot_101420_063819_PM

Initializing the database in a web worker won't work, because it doesn't share memory with the main thread. The database is not Deserialize + Serialize, so you can't send it over manually either. I considered raw JS interop with one of the libphonenumber-based NPM packages out there, but there would be no way to convert the result to a phonenumber::PhoneNumber, since the struct is encapsulated such that the only way to make one is by parsing from a string. That leaves the most promising option as an unnecessary client type, something like

pub enum ClientPhoneNumber {
    PhoneNumber(phonenumber::PhoneNumber),
    DefinitelyAValidPhoneNumberIPromise(String),
}

and leaving the final say to the backend. This is certainly possible, but negates a lot of the benefit of having a unified client+server in full-stack Rust.

PartialEq/Eq implementations do not satisfy the semantics of Eq

Discovered in #53, by trying this:

diff --git a/src/phone_number.rs b/src/phone_number.rs
index fe028ef..8f466e0 100644
--- a/src/phone_number.rs
+++ b/src/phone_number.rs
@@ -294,10 +294,12 @@ mod test {
         };

         let formatted = number.format().mode(mode).to_string();
-        parser::parse(country_hint, &formatted).with_context(|| {
+        let parsed = parser::parse(country_hint, &formatted).with_context(|| {
             format!("parsing {number} after formatting in {mode:?} mode as {formatted}")
         })?;

+        assert_eq!(number, parsed);
+
         Ok(())
     }
 }

I discovered that the PhoneNumber Eq implementation is a bit wonky in my opinion:

---- phone_number::test::round_trip_parsing::case_2::mode_4_Mode__National stdout ----
thread 'phone_number::test::round_trip_parsing::case_2::mode_4_Mode__National' panicked at 'assertion failed: `(left == right)`
  left: `PhoneNumber { code: Code { value: 32, source: Plus }, national: NationalNumber { value: 474091150, zeros: 0 }, extension: None, carrier: None }`,
 right: `PhoneNumber { code: Code { value: 32, source: Default }, national: NationalNumber { value: 474091150, zeros: 0 }, extension: None, carrier: None }`',
src/phone_number.rs:301:9

I would expect those two numbers to satisfy Eq, but since they are parsed differently, they are not.

Should we reconsider PartialEq/Eq implementations?

Update google libphonenumber to latest version.

rust-phonenumber is currently quite a long way behind Google libphonenumber (currently version 8.12.31) - so users of the project do not get the advantage of changes in number plans.

It would be really helpful if rust-phonenumber took updated versions of the libphonenumber assets.

Panic when parsing malformed phone number

#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &str| {
    phonenumber::parse(None, data);
});

Input: " 2 22#:"

stack trace:

thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', /home/jess/src/rust-phonenumber/src/parser/natural.rs:31:31
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
==1196841== ERROR: libFuzzer: deadly signal
    #0 0x558960d73251 in __sanitizer_print_stack_trace /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:87:3
    #1 0x5589618a01f8 in fuzzer::PrintStackTrace() (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x124a1f8)
    #2 0x55896187a2d5 in fuzzer::Fuzzer::CrashCallback() (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x12242d5)
    #3 0x7f5e7670b86f  (/usr/lib/libpthread.so.0+0x1386f)
    #4 0x7f5e7641bd21 in raise (/usr/lib/libc.so.6+0x3cd21)
    #5 0x7f5e76405861 in abort (/usr/lib/libc.so.6+0x26861)
    #6 0x558961927796 in std::sys::unix::abort_internal::h2b5353982e294b6c /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/std/src/sys/unix/mod.rs:259:14
    #7 0x558960cecac5 in std::process::abort::h64b8d5b89778f542 /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/std/src/process.rs:1987:5
    #8 0x558961865765 in libfuzzer_sys::initialize::_$u7b$$u7b$closure$u7d$$u7d$::h811575f9bb402bcd (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x120f765)
    #9 0x55896191be48 in std::panicking::rust_panic_with_hook::hf8e86850fbbd03b1 /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/std/src/panicking.rs:610:17
    #10 0x55896191b8d1 in std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::h590a0d6060ff866e /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/std/src/panicking.rs:500:13
    #11 0x558961918893 in std::sys_common::backtrace::__rust_end_short_backtrace::h260b8bd1c848a03c /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/std/src/sys_common/backtrace.rs:139:18
    #12 0x55896191b868 in rust_begin_unwind /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/std/src/panicking.rs:498:5
    #13 0x558960cee030 in core::panicking::panic_fmt::h7b8580d81fcbbacd /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/core/src/panicking.rs:106:14
    #14 0x558960cedf7c in core::panicking::panic::h50b51d19800453c0 /rustc/8b09ba6a5d5c644fe0f1c27c7f9c80b334241707/library/core/src/panicking.rs:47:5
    #15 0x558960f8b253 in phonenumber::parser::natural::phone_number::h0fa34d8d9465ee72 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x935253)
    #16 0x558960ee6028 in _$LT$$LP$A$C$B$RP$$u20$as$u20$nom..branch..Alt$LT$Input$C$Output$C$Error$GT$$GT$::choice::hb1d4cb7a3a5ac067 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x890028)
    #17 0x558960f905e2 in phonenumber::parser::parse_with::phone_number::h6f3cab01067dc854 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x93a5e2)
    #18 0x558960d9e78b in phonenumber::parser::parse_with::h67d248e390f231c7 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x74878b)
    #19 0x558960db9fbb in rust_fuzzer_test_input (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x763fbb)
    #20 0x5589618658b8 in __rust_try (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x120f8b8)
    #21 0x558961864d88 in LLVMFuzzerTestOneInput (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x120ed88)
    #22 0x55896187a811 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x1224811)
    #23 0x55896187fe1f in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x1229e1f)
    #24 0x558961880d18 in fuzzer::Fuzzer::MutateAndTestOne() (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x122ad18)
    #25 0x558961883117 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x122d117)
    #26 0x558961873d50 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x121dd50)
    #27 0x558960cee802 in main (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x698802)
    #28 0x7f5e76406b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
    #29 0x558960cee9ad in _start (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x6989ad)

Numbers starting with the same sequence as country prefix are parsed incorrectly

Test case:

3912312312 is parsed with the lastest main as 12312312

PhoneNumber {
        code: Code {
            value: 39,
            source: Number,
        },
        national: NationalNumber {
            value: 12312312,
        },
        extension: None,
        carrier: None,
    }

libphone parses this number correctly:

****Parsing Result:****
{"country_code":39,"national_number":3912312312,"raw_input":"3912312312","country_code_source":20}

****Validation Results:****
Result from isPossibleNumber(): true
Result from isValidNumber(): true
Result from isValidNumberForRegion(): true
Phone Number region: IT
Result from getNumberType(): MOBILE

****Formatting Results:**** 
E164 format: +393912312312
Original format: 391 231 2312
National format: 391 231 2312
International format: +39 391 231 2312
Out-of-country format from US: 011 39 391 231 2312
Out-of-country format from Switzerland: 00 39 391 231 2312
Format for mobile dialing (calling from US): +39 391 231 2312
Format for national dialing with preferred carrier code and empty fallback carrier code: 391 231 2312

Compile Error: expected enum `nom::Err`, found enum `nom::ErrorKind`

When use this crate with other crates like magick-rust, the type of IResult::Error is somehow changed. Therefore, the compilation ends with errors,

error[E0308]: mismatched types
  --> src/parser/helper.rs:71:25
   |
71 |         return IResult::Error(nom::ErrorKind::RegexpMatch);
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                               |
   |                               expected enum `nom::Err`, found enum `nom::ErrorKind`
   |                               help: try using a variant of the expected type: `nom::Err::Code(nom::ErrorKind::RegexpMatch)`
   |
   = note: expected type `nom::Err<&str>`
              found type `nom::ErrorKind<_>`

error[E0308]: mismatched types
  --> src/parser/helper.rs:83:18
   |
83 |         IResult::Error(nom::ErrorKind::RegexpMatch)
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                        |
   |                        expected enum `nom::Err`, found enum `nom::ErrorKind`
   |                        help: try using a variant of the expected type: `nom::Err::Code(nom::ErrorKind::RegexpMatch)`
   |
   = note: expected type `nom::Err<&str>`
              found type `nom::ErrorKind<_>`

error[E0308]: mismatched types
  --> src/parser/rfc3966.rs:79:18
   |
79 |         IResult::Error(nom::ErrorKind::Tag)
   |                        ^^^^^^^^^^^^^^^^^^^
   |                        |
   |                        expected enum `nom::Err`, found enum `nom::ErrorKind`
   |                        help: try using a variant of the expected type: `nom::Err::Code(nom::ErrorKind::Tag)`
   |
   = note: expected type `nom::Err<&str>`
              found type `nom::ErrorKind<_>`

General formatting

At the moment most files are not formatted with the rustfmt formatter. It would be good to use this generally used standard for the code.

Command:

$ cargo fmt
$ git diff --name-only

Output:

build.rs
examples/test.rs
src/carrier.rs
src/consts.rs
src/country.rs
src/error.rs
src/extension.rs
src/formatter.rs
src/helper.rs
src/lib.rs
src/metadata/database.rs
src/metadata/descriptor.rs
src/metadata/format.rs
src/metadata/loader.rs
src/metadata/metadata.rs
src/metadata/mod.rs
src/national_number.rs
src/parser/helper.rs
src/parser/mod.rs
src/parser/natural.rs
src/parser/rfc3966.rs
src/parser/valid.rs
src/phone_number.rs
src/validator.rs

failure dependency is deprecated

Hi - I have a build using phonenumber, and cargo audit is now reporting

Crate:  failure
Title:  failure is officially deprecated/unmaintained
Date:   2020-05-02
URL:    https://rustsec.org/advisories/RUSTSEC-2020-0036
Dependency tree:
failure 0.1.8
└── phonenumber 0.2.4+8.11.3

Is there any plan to move off failure to something else, e.g., anyhow/thiserror?

Mutation methods?

Is there any plan to add methods to change parts of a PhoneNumber or create a new one based on an existing one? E.g. set_extension?

I'd rather not rely on getters + string manipulation, since that's the kind of fiddly stuff I'm trying to avoid by using a library. I'd also worry about getting things subtly wrong. I had no idea how deep the international phone number rabbit hole went before I found libphonenumber... :)

Refactoring `Database`: `const` and faster loading, dropping bincode-loading

At the moment the Database is quite a complex data structure.
I would like to make a single static database, but I'm not sure if that fit's with the design goals of the library.
So in an effort to clarify what the design goals of the library are, I have some questions:

  • Is there a concrete use case for loading a database that's not the default?
    The fn parse_with accepts a database param, is that used by the community?

    • If there is no concrete case, then maybe the Database can become a static structure represented as Rust source code
      generated from the assets/PhoneNumberMetadata.xml?
  • The bincode (Vec<Meatadata>) is processed on first use (through lazy_static at time of writing) into a Database which is a composite of a RegexCache and three HashMaps.
    This cache and HashMap generation has quite the runtime cost. It looks like it can be created offline and then stored as bincode. Then it's simply a matter of loading the database at runtime.

Output of PhoneNumber format using International doesn't parse in PhoneNumber::from_str (i.e. roundtrip fails)

The phone number "+1 800 723 3456" parses fine as expected. Then the formatted output is "+1 800-723-3456", but this fails to parse. Though "+1-800-723-3456" successfully parses.

I'd suggest being more forgiving in PhoneNumber::from_str and just entirely ignoring spaces and hyphens, and potentially other characters. At the very least, make it so PhoneNumber::from_str can successfully parse its own formatted output.

Example code:

#[test]
fn test() {
    use phonenumber::{Mode, PhoneNumber};
    let original_phone_number_string = String::from("+1 800 723 3456");
    println!("original_phone_number_string: {:?}", original_phone_number_string);
    let parsed_phone_number = PhoneNumber::from_str(&original_phone_number_string).unwrap();
    println!("parsed_phone_number: {:?}", parsed_phone_number);
    let formatted_phone_number_string = parsed_phone_number.format().mode(Mode::International).to_string();
    println!("formatted_phone_number_string: {:?}", formatted_phone_number_string);
    // This call fails, and we panic on the unwrap for dramatic purposes.
    let reparsed_phone_number = PhoneNumber::from_str(&formatted_phone_number_string).unwrap();
    println!("reparsed_phone_number: {:?}", reparsed_phone_number);
}

Is there some documentation somewhere indicating what formats are accepted by PhoneNumber::from_str? I poked around the google libphonenumber repo a bit but didn't see anything obvious either.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.